1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: Options parsing
4 //
5 // Code available from: https://verilator.org
6 //
7 //*************************************************************************
8 //
9 // Copyright 2003-2021 by Wilson Snyder. This program is free software; you
10 // can redistribute it and/or modify it under the terms of either the GNU
11 // Lesser General Public License Version 3 or the Perl Artistic License
12 // Version 2.0.
13 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
14 //
15 //*************************************************************************
16
17 #include "config_build.h"
18 #include "verilatedos.h"
19
20 #include "V3Global.h"
21 #include "V3Ast.h"
22 #include "V3Os.h"
23 #include "V3Options.h"
24 #include "V3OptionParser.h"
25 #include "V3Error.h"
26 #include "V3File.h"
27 #include "V3PreShell.h"
28 #include "V3String.h"
29
30 // clang-format off
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #ifndef _WIN32
34 # include <sys/utsname.h>
35 #endif
36 #include <algorithm>
37 #include <cctype>
38 #include <dirent.h>
39 #include <fcntl.h>
40 #include <list>
41 #include <map>
42 #include <memory>
43 #include <set>
44
45 #include "config_rev.h"
46
47 #if defined(_WIN32) || defined(__MINGW32__)
48 # include <io.h> // open, close
49 #endif
50 // clang-format on
51
52 //######################################################################
53 // V3 Internal state
54
55 class V3OptionsImp final {
56 public:
57 // TYPES
58 using DirMap = std::map<const string, std::set<std::string>>; // Directory listing
59
60 // STATE
61 std::list<string> m_allArgs; // List of every argument encountered
62 std::list<string> m_incDirUsers; // Include directories (ordered)
63 std::set<string> m_incDirUserSet; // Include directories (for removing duplicates)
64 std::list<string> m_incDirFallbacks; // Include directories (ordered)
65 std::set<string> m_incDirFallbackSet; // Include directories (for removing duplicates)
66 std::map<const string, V3LangCode> m_langExts; // Language extension map
67 std::list<string> m_libExtVs; // Library extensions (ordered)
68 std::set<string> m_libExtVSet; // Library extensions (for removing duplicates)
69 DirMap m_dirMap; // Directory listing
70
71 // ACCESSOR METHODS
addIncDirUser(const string & incdir)72 void addIncDirUser(const string& incdir) {
73 if (m_incDirUserSet.find(incdir) == m_incDirUserSet.end()) {
74 // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
75 m_incDirUserSet.insert(incdir);
76 m_incDirUsers.push_back(incdir);
77 m_incDirFallbacks.remove(incdir); // User has priority over Fallback
78 m_incDirFallbackSet.erase(incdir); // User has priority over Fallback
79 }
80 }
addIncDirFallback(const string & incdir)81 void addIncDirFallback(const string& incdir) {
82 if (m_incDirUserSet.find(incdir)
83 == m_incDirUserSet.end()) { // User has priority over Fallback
84 if (m_incDirFallbackSet.find(incdir) == m_incDirFallbackSet.end()) {
85 // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
86 m_incDirFallbackSet.insert(incdir);
87 m_incDirFallbacks.push_back(incdir);
88 }
89 }
90 }
addLangExt(const string & langext,const V3LangCode & lc)91 void addLangExt(const string& langext, const V3LangCode& lc) {
92 // New language extension replaces any pre-existing one.
93 (void)m_langExts.erase(langext);
94 m_langExts[langext] = lc;
95 }
96
addLibExtV(const string & libext)97 void addLibExtV(const string& libext) {
98 if (m_libExtVSet.find(libext) == m_libExtVSet.end()) {
99 // cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
100 m_libExtVSet.insert(libext);
101 m_libExtVs.push_back(libext);
102 }
103 }
104 V3OptionsImp() = default;
105 ~V3OptionsImp() = default;
106 };
107
108 //######################################################################
109 // V3LangCode class functions
110
V3LangCode(const char * textp)111 V3LangCode::V3LangCode(const char* textp) {
112 // Return code for given string, or ERROR, which is a bad code
113 for (int codei = V3LangCode::L_ERROR; codei < V3LangCode::_ENUM_END; ++codei) {
114 const V3LangCode code = V3LangCode(codei);
115 if (0 == VL_STRCASECMP(textp, code.ascii())) {
116 m_e = code;
117 return;
118 }
119 }
120 m_e = V3LangCode::L_ERROR;
121 }
122
123 //######################################################################
124 // VTimescale class functions
125
VTimescale(const string & value,bool & badr)126 VTimescale::VTimescale(const string& value, bool& badr)
127 : m_e{VTimescale::NONE} {
128 badr = true;
129 const string spaceless = VString::removeWhitespace(value);
130 for (int i = TS_100S; i < _ENUM_END; ++i) {
131 const VTimescale ts(i);
132 if (spaceless == ts.ascii()) {
133 badr = false;
134 m_e = ts.m_e;
135 break;
136 }
137 }
138 }
139
140 //######################################################################
141 // V3HierarchicalBlockOption class functions
142
143 // Parse "--hierarchical-block orig_name,mangled_name,param0_name,param0_value,... " option.
144 // The format of value is as same as -G option. (can be string literal surrounded by ")
V3HierarchicalBlockOption(const string & opts)145 V3HierarchicalBlockOption::V3HierarchicalBlockOption(const string& opts) {
146 V3StringList vals;
147 bool inStr = false;
148 string cur;
149 static const string hierBlock("--hierarchical-block");
150 FileLine cmdfl(FileLine::commandLineFilename());
151 // Split by ','. If ',' appears between "", that is not a separator.
152 for (string::const_iterator it = opts.begin(); it != opts.end();) {
153 if (inStr) {
154 if (*it == '\\') {
155 ++it;
156 if (it == opts.end()) {
157 cmdfl.v3error(hierBlock + " must not end with \\");
158 break;
159 }
160 if (*it != '"' && *it != '\\') {
161 cmdfl.v3error(hierBlock + " does not allow '" + *it + "' after \\");
162 break;
163 }
164 cur.push_back(*it);
165 ++it;
166 } else if (*it == '"') { // end of string
167 cur.push_back(*it);
168 vals.push_back(cur);
169 cur.clear();
170 ++it;
171 if (it != opts.end()) {
172 if (*it != ',') {
173 cmdfl.v3error(hierBlock + " expects ',', but '" + *it + "' is passed");
174 break;
175 }
176 ++it;
177 if (it == opts.end()) {
178 cmdfl.v3error(hierBlock + " must not end with ','");
179 break;
180 }
181 inStr = *it == '"';
182 cur.push_back(*it);
183 ++it;
184 }
185 } else {
186 cur.push_back(*it);
187 ++it;
188 }
189 } else {
190 if (*it == '"') {
191 cmdfl.v3error(hierBlock + " does not allow '\"' in the middle of literal");
192 break;
193 }
194 if (*it == ',') { // end of this parameter
195 vals.push_back(cur);
196 cur.clear();
197 ++it;
198 if (it == opts.end()) {
199 cmdfl.v3error(hierBlock + " must not end with ','");
200 break;
201 }
202 inStr = *it == '"';
203 }
204 cur.push_back(*it);
205 ++it;
206 }
207 }
208 if (!cur.empty()) vals.push_back(cur);
209 if (vals.size() >= 2) {
210 if (vals.size() % 2) {
211 cmdfl.v3error(hierBlock + " requires the number of entries to be even");
212 }
213 m_origName = vals[0];
214 m_mangledName = vals[1];
215 } else {
216 cmdfl.v3error(hierBlock + " requires at least two comma-separated values");
217 }
218 for (size_t i = 2; i + 1 < vals.size(); i += 2) {
219 const bool inserted = m_parameters.insert(std::make_pair(vals[i], vals[i + 1])).second;
220 if (!inserted) {
221 cmdfl.v3error("Module name '" + vals[i] + "' is duplicated in " + hierBlock);
222 }
223 }
224 }
225
226 //######################################################################
227 // V3Options class functions
228
parseSlashed(FileLine * fl,const char * textp,VTimescale & unitr,VTimescale & precr,bool allowEmpty)229 void VTimescale::parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr,
230 VTimescale& precr, bool allowEmpty) {
231 // Parse `timescale of <number><units> / <number><units>
232 unitr = VTimescale::NONE;
233 precr = VTimescale::NONE;
234
235 const char* cp = textp;
236 for (; isspace(*cp); ++cp) {}
237 const char* const unitp = cp;
238 for (; *cp && *cp != '/'; ++cp) {}
239 const string unitStr(unitp, cp - unitp);
240 for (; isspace(*cp); ++cp) {}
241 string precStr;
242 if (*cp == '/') {
243 ++cp;
244 for (; isspace(*cp); ++cp) {}
245 const char* const precp = cp;
246 for (; *cp && *cp != '/'; ++cp) {}
247 precStr = string(precp, cp - precp);
248 }
249 for (; isspace(*cp); ++cp) {}
250 if (*cp) {
251 fl->v3error("`timescale syntax error: '" << textp << "'");
252 return;
253 }
254
255 bool unitbad;
256 const VTimescale unit(unitStr, unitbad /*ref*/);
257 if (unitbad && !(unitStr.empty() && allowEmpty)) {
258 fl->v3error("`timescale timeunit syntax error: '" << unitStr << "'");
259 return;
260 }
261 unitr = unit;
262
263 if (!precStr.empty()) {
264 VTimescale prec(VTimescale::NONE);
265 bool precbad;
266 prec = VTimescale(precStr, precbad /*ref*/);
267 if (precbad) {
268 fl->v3error("`timescale timeprecision syntax error: '" << precStr << "'");
269 return;
270 }
271 if (!unit.isNone() && !prec.isNone() && unit < prec) {
272 fl->v3error("`timescale timeunit '"
273 << unitStr << "' must be greater than or equal to timeprecision '"
274 << precStr << "'");
275 return;
276 }
277 precr = prec;
278 }
279 }
280
281 //######################################################################
282 // V3Options class functions
283
addIncDirUser(const string & incdir)284 void V3Options::addIncDirUser(const string& incdir) { m_impp->addIncDirUser(incdir); }
addIncDirFallback(const string & incdir)285 void V3Options::addIncDirFallback(const string& incdir) { m_impp->addIncDirFallback(incdir); }
addLangExt(const string & langext,const V3LangCode & lc)286 void V3Options::addLangExt(const string& langext, const V3LangCode& lc) {
287 m_impp->addLangExt(langext, lc);
288 }
addLibExtV(const string & libext)289 void V3Options::addLibExtV(const string& libext) { m_impp->addLibExtV(libext); }
addDefine(const string & defline,bool allowPlus)290 void V3Options::addDefine(const string& defline, bool allowPlus) {
291 // Split +define+foo=value into the appropriate parts and parse
292 // Optional + says to allow multiple defines on the line
293 // + is not quotable, as other simulators do not allow that
294 string left = defline;
295 while (left != "") {
296 string def = left;
297 string::size_type pos;
298 if (allowPlus && ((pos = left.find('+')) != string::npos)) {
299 left = left.substr(pos + 1);
300 def.erase(pos);
301 } else {
302 left = "";
303 }
304 string value;
305 if ((pos = def.find('=')) != string::npos) {
306 value = def.substr(pos + 1);
307 def.erase(pos);
308 }
309 V3PreShell::defineCmdLine(def, value);
310 }
311 }
addParameter(const string & paramline,bool allowPlus)312 void V3Options::addParameter(const string& paramline, bool allowPlus) {
313 // Split +define+foo=value into the appropriate parts and parse
314 // Optional + says to allow multiple defines on the line
315 // + is not quotable, as other simulators do not allow that
316 string left = paramline;
317 while (left != "") {
318 string param = left;
319 string::size_type pos;
320 if (allowPlus && ((pos = left.find('+')) != string::npos)) {
321 left = left.substr(pos + 1);
322 param.erase(pos);
323 } else {
324 left = "";
325 }
326 string value;
327 if ((pos = param.find('=')) != string::npos) {
328 value = param.substr(pos + 1);
329 param.erase(pos);
330 }
331 UINFO(4, "Add parameter" << param << "=" << value << endl);
332 (void)m_parameters.erase(param);
333 m_parameters[param] = value;
334 }
335 }
336
hasParameter(const string & name)337 bool V3Options::hasParameter(const string& name) {
338 return m_parameters.find(name) != m_parameters.end();
339 }
340
parameter(const string & name)341 string V3Options::parameter(const string& name) {
342 const string value = m_parameters.find(name)->second;
343 m_parameters.erase(m_parameters.find(name));
344 return value;
345 }
346
checkParameters()347 void V3Options::checkParameters() {
348 if (!m_parameters.empty()) {
349 std::stringstream msg;
350 msg << "Parameters from the command line were not found in the design:";
351 for (const auto& i : m_parameters) msg << " " << i.first;
352 v3error(msg.str());
353 }
354 }
355
addCppFile(const string & filename)356 void V3Options::addCppFile(const string& filename) { m_cppFiles.insert(filename); }
addCFlags(const string & filename)357 void V3Options::addCFlags(const string& filename) { m_cFlags.push_back(filename); }
addLdLibs(const string & filename)358 void V3Options::addLdLibs(const string& filename) { m_ldLibs.push_back(filename); }
addMakeFlags(const string & filename)359 void V3Options::addMakeFlags(const string& filename) { m_makeFlags.push_back(filename); }
addFuture(const string & flag)360 void V3Options::addFuture(const string& flag) { m_futures.insert(flag); }
isFuture(const string & flag) const361 bool V3Options::isFuture(const string& flag) const {
362 return m_futures.find(flag) != m_futures.end();
363 }
isLibraryFile(const string & filename) const364 bool V3Options::isLibraryFile(const string& filename) const {
365 return m_libraryFiles.find(filename) != m_libraryFiles.end();
366 }
addLibraryFile(const string & filename)367 void V3Options::addLibraryFile(const string& filename) { m_libraryFiles.insert(filename); }
isClocker(const string & signame) const368 bool V3Options::isClocker(const string& signame) const {
369 return m_clockers.find(signame) != m_clockers.end();
370 }
addClocker(const string & signame)371 void V3Options::addClocker(const string& signame) { m_clockers.insert(signame); }
isNoClocker(const string & signame) const372 bool V3Options::isNoClocker(const string& signame) const {
373 return m_noClockers.find(signame) != m_noClockers.end();
374 }
addNoClocker(const string & signame)375 void V3Options::addNoClocker(const string& signame) { m_noClockers.insert(signame); }
addVFile(const string & filename)376 void V3Options::addVFile(const string& filename) {
377 // We use a list for v files, because it's legal to have includes
378 // in a specific order and multiple of them.
379 m_vFiles.push_back(filename);
380 }
addForceInc(const string & filename)381 void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(filename); }
382
addArg(const string & arg)383 void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); }
384
allArgsString() const385 string V3Options::allArgsString() const {
386 string out;
387 for (const string& i : m_impp->m_allArgs) {
388 if (out != "") out += " ";
389 out += i;
390 }
391 return out;
392 }
393
394 // Delete some options for Verilation of the hierarchical blocks.
allArgsStringForHierBlock(bool forTop) const395 string V3Options::allArgsStringForHierBlock(bool forTop) const {
396 std::set<string> vFiles;
397 for (const auto& vFile : m_vFiles) vFiles.insert(vFile);
398 string out;
399 for (std::list<string>::const_iterator it = m_impp->m_allArgs.begin();
400 it != m_impp->m_allArgs.end(); ++it) {
401 int skip = 0;
402 if (it->length() >= 2 && (*it)[0] == '-' && (*it)[1] == '-') {
403 skip = 2;
404 } else if (it->length() >= 1 && (*it)[0] == '-') {
405 skip = 1;
406 }
407 if (skip > 0) { // *it is an option
408 const string opt = it->substr(skip); // Remove '-' in the beginning
409 const int numStrip = stripOptionsForChildRun(opt, forTop);
410 if (numStrip) {
411 UASSERT(0 <= numStrip && numStrip <= 2, "should be one of 0, 1, 2");
412 if (numStrip == 2) ++it;
413 continue;
414 }
415 } else { // Not an option
416 if (vFiles.find(*it) != vFiles.end() // Remove HDL
417 || m_cppFiles.find(*it) != m_cppFiles.end()) { // Remove C++
418 continue;
419 }
420 }
421 if (out != "") out += " ";
422 // Don't use opt here because '-' is removed in it
423 // Use double quote because *it may contain whitespaces
424 out += '"' + VString::quoteAny(*it, '"', '\\') + '"';
425 }
426 return out;
427 }
428
429 //######################################################################
430 // File searching
431
fileStatNormal(const string & filename)432 bool V3Options::fileStatNormal(const string& filename) {
433 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
434 struct stat sstat; // Stat information
435 const int err = stat(filename.c_str(), &sstat);
436 if (err != 0) return false;
437 if (S_ISDIR(sstat.st_mode)) return false;
438 return true;
439 }
440
fileNfsFlush(const string & filename)441 void V3Options::fileNfsFlush(const string& filename) {
442 // NFS caches stat() calls so to get up-to-date information must
443 // do a open or opendir on the filename.
444 // Faster to just try both rather than check if a file is a dir.
445 if (DIR* const dirp = opendir(filename.c_str())) { // LCOV_EXCL_BR_LINE
446 closedir(dirp); // LCOV_EXCL_LINE
447 } else if (int fd = ::open(filename.c_str(), O_RDONLY)) { // LCOV_EXCL_BR_LINE
448 if (fd > 0) ::close(fd);
449 }
450 }
451
fileExists(const string & filename)452 string V3Options::fileExists(const string& filename) {
453 // Surprisingly, for VCS and other simulators, this process
454 // is quite slow; presumably because of re-reading each directory
455 // many times. So we read a whole dir at once and cache it
456
457 const string dir = V3Os::filenameDir(filename);
458 const string basename = V3Os::filenameNonDir(filename);
459
460 auto diriter = m_impp->m_dirMap.find(dir);
461 if (diriter == m_impp->m_dirMap.end()) {
462 // Read the listing
463 m_impp->m_dirMap.emplace(dir, std::set<string>());
464 diriter = m_impp->m_dirMap.find(dir);
465
466 std::set<string>* setp = &(diriter->second);
467
468 if (DIR* const dirp = opendir(dir.c_str())) {
469 while (struct dirent* direntp = readdir(dirp)) setp->insert(direntp->d_name);
470 closedir(dirp);
471 }
472 }
473 // Find it
474 const std::set<string>* filesetp = &(diriter->second);
475 const auto fileiter = filesetp->find(basename);
476 if (fileiter == filesetp->end()) {
477 return ""; // Not found
478 }
479 // Check if it is a directory, ignore if so
480 const string filenameOut = V3Os::filenameFromDirBase(dir, basename);
481 if (!fileStatNormal(filenameOut)) return ""; // Directory
482 return filenameOut;
483 }
484
filePathCheckOneDir(const string & modname,const string & dirname)485 string V3Options::filePathCheckOneDir(const string& modname, const string& dirname) {
486 for (const string& i : m_impp->m_libExtVs) {
487 const string fn = V3Os::filenameFromDirBase(dirname, modname + i);
488 string exists = fileExists(fn);
489 if (exists != "") {
490 // Strip ./, it just looks ugly
491 if (exists.substr(0, 2) == "./") exists.erase(0, 2);
492 return exists;
493 }
494 }
495 return "";
496 }
497
498 // Checks if a option needs to be stripped for child run of hierarchical Verilation.
499 // 0: Keep the option including its argument
500 // 1: Delete the option which has no argument
501 // 2: Delete the option and its argument
stripOptionsForChildRun(const string & opt,bool forTop)502 int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) {
503 if (opt == "Mdir" || opt == "clk" || opt == "lib-create" || opt == "f" || opt == "j"
504 || opt == "l2-name" || opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib"
505 || opt == "protect-key" || opt == "threads" || opt == "top-module" || opt == "v") {
506 return 2;
507 }
508 if (opt == "build" || (!forTop && (opt == "cc" || opt == "exe" || opt == "sc"))
509 || opt == "hierarchical" || (opt.length() > 2 && opt.substr(0, 2) == "G=")) {
510 return 1;
511 }
512 return 0;
513 }
514
filePath(FileLine * fl,const string & modname,const string & lastpath,const string & errmsg)515 string V3Options::filePath(FileLine* fl, const string& modname, const string& lastpath,
516 const string& errmsg) { // Error prefix or "" to suppress error
517 // Find a filename to read the specified module name,
518 // using the incdir and libext's.
519 // Return "" if not found.
520 for (const string& dir : m_impp->m_incDirUsers) {
521 const string exists = filePathCheckOneDir(modname, dir);
522 if (exists != "") return exists;
523 }
524 for (const string& dir : m_impp->m_incDirFallbacks) {
525 const string exists = filePathCheckOneDir(modname, dir);
526 if (exists != "") return exists;
527 }
528
529 if (m_relativeIncludes) {
530 const string exists = filePathCheckOneDir(modname, lastpath);
531 if (exists != "") return V3Os::filenameRealPath(exists);
532 }
533
534 // Warn and return not found
535 if (errmsg != "") {
536 fl->v3error(errmsg + modname);
537 filePathLookedMsg(fl, modname);
538 }
539 return "";
540 }
541
filePathLookedMsg(FileLine * fl,const string & modname)542 void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
543 static bool shown_notfound_msg = false;
544 if (modname.find("__Vhsh") != string::npos) {
545 std::cerr << V3Error::warnMore() << "... Unsupported: Name is longer than 127 characters;"
546 << " automatic file lookup not supported.\n";
547 std::cerr << V3Error::warnMore() << "... Suggest putting filename with this module/package"
548 << " onto command line instead.\n";
549 } else if (!shown_notfound_msg) {
550 shown_notfound_msg = true;
551 if (m_impp->m_incDirUsers.empty()) {
552 fl->v3error("This may be because there's no search path specified with -I<dir>.");
553 }
554 std::cerr << V3Error::warnMore() << "... Looked in:" << endl;
555 for (const string& dir : m_impp->m_incDirUsers) {
556 for (const string& ext : m_impp->m_libExtVs) {
557 const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
558 std::cerr << V3Error::warnMore() << " " << fn << endl;
559 }
560 }
561 for (const string& dir : m_impp->m_incDirFallbacks) {
562 for (const string& ext : m_impp->m_libExtVs) {
563 const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
564 std::cerr << V3Error::warnMore() << " " << fn << endl;
565 }
566 }
567 }
568 }
569
570 //! Determine what language is associated with a filename
571
572 //! If we recognize the extension, use its language, otherwise, use the
573 //! default language.
fileLanguage(const string & filename)574 V3LangCode V3Options::fileLanguage(const string& filename) {
575 string ext = V3Os::filenameNonDir(filename);
576 string::size_type pos;
577 if ((pos = ext.rfind('.')) != string::npos) {
578 ext.erase(0, pos + 1);
579 const auto it = m_impp->m_langExts.find(ext);
580 if (it != m_impp->m_langExts.end()) return it->second;
581 }
582 return m_defaultLanguage;
583 }
584
585 //######################################################################
586 // Environment
587
getenvBuiltins(const string & var)588 string V3Options::getenvBuiltins(const string& var) {
589 if (var == "MAKE") {
590 return getenvMAKE();
591 } else if (var == "PERL") {
592 return getenvPERL();
593 } else if (var == "SYSTEMC") {
594 return getenvSYSTEMC();
595 } else if (var == "SYSTEMC_ARCH") {
596 return getenvSYSTEMC_ARCH();
597 } else if (var == "SYSTEMC_INCLUDE") {
598 return getenvSYSTEMC_INCLUDE();
599 } else if (var == "SYSTEMC_LIBDIR") {
600 return getenvSYSTEMC_LIBDIR();
601 } else if (var == "VERILATOR_ROOT") {
602 return getenvVERILATOR_ROOT();
603 } else {
604 return V3Os::getenvStr(var, "");
605 }
606 }
607
608 #ifdef __FreeBSD__
getenvMAKE()609 string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "gmake"); }
610 #else
getenvMAKE()611 string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "make"); }
612 #endif
613
getenvPERL()614 string V3Options::getenvPERL() { //
615 return V3Os::getenvStr("PERL", "perl");
616 }
617
getenvSYSTEMC()618 string V3Options::getenvSYSTEMC() {
619 string var = V3Os::getenvStr("SYSTEMC", "");
620 if (var == "" && string(DEFENV_SYSTEMC) != "") {
621 var = DEFENV_SYSTEMC;
622 V3Os::setenvStr("SYSTEMC", var, "Hardcoded at build time");
623 }
624 return var;
625 }
626
getenvSYSTEMC_ARCH()627 string V3Options::getenvSYSTEMC_ARCH() {
628 string var = V3Os::getenvStr("SYSTEMC_ARCH", "");
629 if (var == "" && string(DEFENV_SYSTEMC_ARCH) != "") {
630 var = DEFENV_SYSTEMC_ARCH;
631 V3Os::setenvStr("SYSTEMC_ARCH", var, "Hardcoded at build time");
632 }
633 if (var == "") {
634 #if defined(__MINGW32__)
635 // Hardcoded with MINGW current version. Would like a better way.
636 const string sysname = "MINGW32_NT-5.0";
637 var = "mingw32";
638 #elif defined(_WIN32)
639 const string sysname = "WIN32";
640 var = "win32";
641 #else
642 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
643 struct utsname uts;
644 uname(&uts);
645 const string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
646 if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*solaris*"))) {
647 var = "gccsparcOS5";
648 } else if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*cygwin*"))) {
649 var = "cygwin";
650 } else {
651 var = "linux";
652 }
653 #endif
654 V3Os::setenvStr("SYSTEMC_ARCH", var, "From sysname '" + sysname + "'");
655 }
656 return var;
657 }
658
getenvSYSTEMC_INCLUDE()659 string V3Options::getenvSYSTEMC_INCLUDE() {
660 string var = V3Os::getenvStr("SYSTEMC_INCLUDE", "");
661 if (var == "" && string(DEFENV_SYSTEMC_INCLUDE) != "") {
662 var = DEFENV_SYSTEMC_INCLUDE;
663 V3Os::setenvStr("SYSTEMC_INCLUDE", var, "Hardcoded at build time");
664 }
665 if (var == "") {
666 const string sc = getenvSYSTEMC();
667 if (sc != "") var = sc + "/include";
668 }
669 return var;
670 }
671
getenvSYSTEMC_LIBDIR()672 string V3Options::getenvSYSTEMC_LIBDIR() {
673 string var = V3Os::getenvStr("SYSTEMC_LIBDIR", "");
674 if (var == "" && string(DEFENV_SYSTEMC_LIBDIR) != "") {
675 var = DEFENV_SYSTEMC_LIBDIR;
676 V3Os::setenvStr("SYSTEMC_LIBDIR", var, "Hardcoded at build time");
677 }
678 if (var == "") {
679 const string sc = getenvSYSTEMC();
680 const string arch = getenvSYSTEMC_ARCH();
681 if (sc != "" && arch != "") var = sc + "/lib-" + arch;
682 }
683 return var;
684 }
685
getenvVERILATOR_ROOT()686 string V3Options::getenvVERILATOR_ROOT() {
687 string var = V3Os::getenvStr("VERILATOR_ROOT", "");
688 if (var == "" && string(DEFENV_VERILATOR_ROOT) != "") {
689 var = DEFENV_VERILATOR_ROOT;
690 V3Os::setenvStr("VERILATOR_ROOT", var, "Hardcoded at build time");
691 }
692 if (var == "") v3fatal("$VERILATOR_ROOT needs to be in environment\n");
693 return var;
694 }
695
systemCSystemWide()696 bool V3Options::systemCSystemWide() {
697 #ifdef HAVE_SYSTEMC
698 return true;
699 #else
700 return false;
701 #endif
702 }
703
systemCFound()704 bool V3Options::systemCFound() {
705 return (systemCSystemWide()
706 || (!getenvSYSTEMC_INCLUDE().empty() && !getenvSYSTEMC_LIBDIR().empty()));
707 }
708
709 //######################################################################
710 // V3 Options notification methods
711
notify()712 void V3Options::notify() {
713 FileLine* const cmdfl = new FileLine(FileLine::commandLineFilename());
714
715 // Notify that all arguments have been passed and final modification can be made.
716 if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) {
717 v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, "
718 "--xml-only or --E option");
719 }
720
721 if (m_build && (m_gmake || m_cmake)) {
722 cmdfl->v3error("--make cannot be used together with --build. Suggest see manual");
723 }
724
725 // Make sure at least one make system is enabled
726 if (!m_gmake && !m_cmake) m_gmake = true;
727
728 if (m_hierarchical && (m_hierChild || !m_hierBlocks.empty())) {
729 cmdfl->v3error(
730 "--hierarchical must not be set with --hierarchical-child or --hierarchical-block");
731 }
732 if (m_hierChild && m_hierBlocks.empty()) {
733 cmdfl->v3error("--hierarchical-block must be set when --hierarchical-child is set");
734 }
735
736 if (protectIds()) {
737 if (allPublic()) {
738 // We always call protect() on names, we don't check if public or not
739 // Hence any external references wouldn't be able to find the refed public object.
740 cmdfl->v3warn(E_UNSUPPORTED, "Unsupported: Using --protect-ids with --public\n" //
741 + V3Error::warnMore()
742 + "... Suggest remove --public.");
743 }
744 if (trace()) {
745 cmdfl->v3warn(INSECURE,
746 "Using --protect-ids with --trace may expose private design details\n"
747 + V3Error::warnMore() + "... Suggest remove --trace.");
748 }
749 if (vpi()) {
750 cmdfl->v3warn(INSECURE,
751 "Using --protect-ids with --vpi may expose private design details\n"
752 + V3Error::warnMore() + "... Suggest remove --vpi.");
753 }
754 }
755
756 // Default some options if not turned on or off
757 if (v3Global.opt.skipIdentical().isDefault()) {
758 v3Global.opt.m_skipIdentical.setTrueOrFalse( //
759 !v3Global.opt.cdc() //
760 && !v3Global.opt.dpiHdrOnly() //
761 && !v3Global.opt.lintOnly() //
762 && !v3Global.opt.preprocOnly() //
763 && !v3Global.opt.xmlOnly());
764 }
765 if (v3Global.opt.makeDepend().isDefault()) {
766 v3Global.opt.m_makeDepend.setTrueOrFalse( //
767 !v3Global.opt.cdc() //
768 && !v3Global.opt.dpiHdrOnly() //
769 && !v3Global.opt.lintOnly() //
770 && !v3Global.opt.preprocOnly() //
771 && !v3Global.opt.xmlOnly());
772 }
773
774 // --trace-threads implies --threads 1 unless explicitly specified
775 if (traceThreads() && !threads()) m_threads = 1;
776
777 // Default split limits if not specified
778 if (m_outputSplitCFuncs < 0) m_outputSplitCFuncs = m_outputSplit;
779 if (m_outputSplitCTrace < 0) m_outputSplitCTrace = m_outputSplit;
780
781 if (v3Global.opt.main() && v3Global.opt.systemC()) {
782 cmdfl->v3warn(E_UNSUPPORTED,
783 "--main not usable with SystemC. Suggest see examples for sc_main().");
784 }
785
786 if (coverage() && savable()) {
787 cmdfl->v3error("--coverage and --savable not supported together");
788 }
789
790 // Mark options as available
791 m_available = true;
792 }
793
794 //######################################################################
795 // V3 Options accessors
796
version()797 string V3Options::version() {
798 string ver = DTVERSION;
799 ver += " rev " + cvtToStr(DTVERSION_rev);
800 return ver;
801 }
802
protectKeyDefaulted()803 string V3Options::protectKeyDefaulted() {
804 if (m_protectKey.empty()) {
805 // Create a key with a human-readable symbol-like name.
806 // This conversion drops ~2 bits of entropy out of 256, shouldn't matter.
807 VHashSha256 digest(V3Os::trueRandom(32));
808 m_protectKey = "VL-KEY-" + digest.digestSymbol();
809 }
810 return m_protectKey;
811 }
812
throwSigsegv()813 void V3Options::throwSigsegv() { // LCOV_EXCL_START
814 #if !(defined(VL_CPPCHECK) || defined(__clang_analyzer__))
815 // clang-format off
816 *static_cast<volatile char*>(nullptr) = 0; // Intentional core dump, ignore warnings here
817 // clang-format on
818 #endif
819 } // LCOV_EXCL_STOP
820
timeComputePrec(const VTimescale & flag) const821 VTimescale V3Options::timeComputePrec(const VTimescale& flag) const {
822 if (!timeOverridePrec().isNone()) {
823 return timeOverridePrec();
824 } else if (flag.isNone()) {
825 return timeDefaultPrec();
826 } else {
827 return flag;
828 }
829 }
830
timeComputeUnit(const VTimescale & flag) const831 VTimescale V3Options::timeComputeUnit(const VTimescale& flag) const {
832 if (!timeOverrideUnit().isNone()) {
833 return timeOverrideUnit();
834 } else if (flag.isNone()) {
835 return timeDefaultUnit();
836 } else {
837 return flag;
838 }
839 }
840
841 //######################################################################
842 // V3 Options utilities
843
argString(int argc,char ** argv)844 string V3Options::argString(int argc, char** argv) {
845 // Return list of arguments as simple string
846 string opts;
847 for (int i = 0; i < argc; ++i) {
848 if (i != 0) opts += " ";
849 opts += string(argv[i]);
850 }
851 return opts;
852 }
853
854 //######################################################################
855 // V3 Options Parsing
856
parseOpts(FileLine * fl,int argc,char ** argv)857 void V3Options::parseOpts(FileLine* fl, int argc, char** argv) {
858 // Parse all options
859 // Initial entry point from Verilator.cpp
860 parseOptsList(fl, ".", argc, argv);
861
862 // Default certain options and error check
863 // Detailed error, since this is what we often get when run with minimal arguments
864 const V3StringList& vFilesList = vFiles();
865 if (vFilesList.empty()) {
866 v3fatal("verilator: No Input Verilog file specified on command line, "
867 "see verilator --help for more information\n");
868 }
869
870 // Default prefix to the filename
871 if (prefix() == "" && topModule() != "")
872 m_prefix = string("V") + AstNode::encodeName(topModule());
873 if (prefix() == "" && vFilesList.size() >= 1)
874 m_prefix = string("V") + AstNode::encodeName(V3Os::filenameNonExt(*(vFilesList.begin())));
875 if (modPrefix() == "") m_modPrefix = prefix();
876
877 // Find files in makedir
878 addIncDirFallback(makeDir());
879 }
880
881 //======================================================================
882
suffixed(const string & sw,const char * arg)883 bool V3Options::suffixed(const string& sw, const char* arg) {
884 if (strlen(arg) > sw.length()) return false;
885 return (0 == strcmp(sw.c_str() + sw.length() - strlen(arg), arg));
886 }
887
parseOptsList(FileLine * fl,const string & optdir,int argc,char ** argv)888 void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) {
889 // Parse parameters
890 // Note argc and argv DO NOT INCLUDE the filename in [0]!!!
891 // May be called recursively when there are -f files.
892 for (int i = 0; i < argc; ++i) {
893 addArg(argv[i]); // -f's really should be inserted in the middle, but this is for debug
894 }
895
896 V3OptionParser parser;
897 const V3OptionParser::AppendHelper DECL_OPTION{parser};
898 V3OPTION_PARSER_DECL_TAGS;
899
900 const auto callStrSetter = [this](void (V3Options::*cbStr)(const string&)) {
901 return [this, cbStr](const string& v) { (this->*cbStr)(v); };
902 };
903 // Usage
904 // DECL_OPTION("-option", action, pointer_or_lambda);
905 // action: one of Set, OnOff, CbCall, CbOnOff, CbVal, CbPartialMatch, and CbPartialMatchVal
906 // Set : Set value to a variable, pointer_or_lambda must be a pointer to the
907 // variable.
908 // true is set to bool-ish variable when '-opt' is passed to verilator.
909 // val is set to int and string variable when '-opt val' is passed.
910 // OnOff : Set value to a bool-ish variable, pointer_or_lambda must be a pointer
911 // to bool or VOptionBool.
912 // true is set if "-opt" is passed to verilator while false is set if
913 // "-no-opt" is given.
914 // CbCall : Call lambda or function that does not take argument.
915 // CbOnOff : Call lambda or function that takes bool argument.
916 // Supports "-opt" and "-no-opt" style options.
917 // CbVal : Call lambda or function that takes int or const char*.
918 // "-opt val" is passed to verilator, val is passed to the lambda.
919 // If a function to be called is a member of V3Options that only takes
920 // const string&, callStrSetter(&V3Options::memberFunc) can be passed
921 // instead of lambda as a syntax sugar.
922 // CbPartialMatch : Call lambda or function that takes remaining string.
923 // e.g. DECL_OPTION("-opt-", CbPartialMatch, [](const char*optp) { cout <<
924 // optp << endl; }); and "-opt-ABC" is passed, "ABC" will be emit to
925 // stdout.
926 // CbPartialMatchVal: Call lambda or function that takes remaining string and value.
927 // e.g. DECL_OPTION("-opt-", CbPartialMatchVal, [](const char*optp, const
928 // char*valp) {
929 // cout << optp << ":" << valp << endl; });
930 // and "-opt-ABC VAL" is passed, "ABC:VAL" will be emit to stdout.
931 //
932 // DECL_OPTION is not C-macro to get correct line coverage even when lambda is passed.
933 // (If DECL_OPTION is a macro, then lambda would be collapsed into a single line).
934
935 // Plus options
936 DECL_OPTION("+define+", CbPartialMatch, [this](const char* optp) { addDefine(optp, true); });
937 DECL_OPTION("+incdir+", CbPartialMatch,
938 [this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); });
939 DECL_OPTION("+libext+", CbPartialMatch, [this](const char* optp) {
940 string exts = optp;
941 string::size_type pos;
942 while ((pos = exts.find('+')) != string::npos) {
943 addLibExtV(exts.substr(0, pos));
944 exts = exts.substr(pos + 1);
945 }
946 addLibExtV(exts);
947 });
948 DECL_OPTION("+librescan", CbCall, []() {}); // NOP
949 DECL_OPTION("+notimingchecks", CbCall, []() {}); // NOP
950 DECL_OPTION("+systemverilogext+", CbPartialMatch,
951 [this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2017); });
952 DECL_OPTION("+verilog1995ext+", CbPartialMatch,
953 [this](const char* optp) { addLangExt(optp, V3LangCode::L1364_1995); });
954 DECL_OPTION("+verilog2001ext+", CbPartialMatch,
955 [this](const char* optp) { addLangExt(optp, V3LangCode::L1364_2001); });
956 DECL_OPTION("+1364-1995ext+", CbPartialMatch,
957 [this](const char* optp) { addLangExt(optp, V3LangCode::L1364_1995); });
958 DECL_OPTION("+1364-2001ext+", CbPartialMatch,
959 [this](const char* optp) { addLangExt(optp, V3LangCode::L1364_2001); });
960 DECL_OPTION("+1364-2005ext+", CbPartialMatch,
961 [this](const char* optp) { addLangExt(optp, V3LangCode::L1364_2005); });
962 DECL_OPTION("+1800-2005ext+", CbPartialMatch,
963 [this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2005); });
964 DECL_OPTION("+1800-2009ext+", CbPartialMatch,
965 [this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2009); });
966 DECL_OPTION("+1800-2012ext+", CbPartialMatch,
967 [this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2012); });
968 DECL_OPTION("+1800-2017ext+", CbPartialMatch,
969 [this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2017); });
970
971 // Minus options
972 DECL_OPTION("-assert", OnOff, &m_assert);
973 DECL_OPTION("-autoflush", OnOff, &m_autoflush);
974
975 DECL_OPTION("-bbox-sys", OnOff, &m_bboxSys);
976 DECL_OPTION("-bbox-unsup", CbOnOff, [this](bool flag) {
977 m_bboxUnsup = flag;
978 FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, true);
979 });
980 DECL_OPTION("-bin", Set, &m_bin);
981 DECL_OPTION("-build", Set, &m_build);
982
983 DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags));
984 DECL_OPTION("-cc", CbCall, [this]() {
985 m_outFormatOk = true;
986 m_systemC = false;
987 });
988 DECL_OPTION("-cdc", OnOff, &m_cdc);
989 DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker));
990 DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker));
991 DECL_OPTION("-comp-limit-blocks", Set, &m_compLimitBlocks).undocumented();
992 DECL_OPTION("-comp-limit-members", Set,
993 &m_compLimitMembers)
994 .undocumented(); // Ideally power-of-two so structs stay aligned
995 DECL_OPTION("-comp-limit-parens", Set, &m_compLimitParens).undocumented();
996 DECL_OPTION("-comp-limit-syms", CbVal, [](int val) { VName::maxLength(val); }).undocumented();
997 DECL_OPTION("-compiler", CbVal, [this, fl](const char* valp) {
998 if (!strcmp(valp, "clang")) {
999 m_compLimitBlocks = 80; // limit unknown
1000 m_compLimitMembers = 64; // soft limit, has slowdown bug as of clang++ 3.8
1001 m_compLimitParens = 80; // limit unknown
1002 } else if (!strcmp(valp, "gcc")) {
1003 m_compLimitBlocks = 0; // Bug free
1004 m_compLimitMembers = 64; // soft limit, has slowdown bug as of g++ 7.1
1005 m_compLimitParens = 0; // Bug free
1006 } else if (!strcmp(valp, "msvc")) {
1007 m_compLimitBlocks = 80; // 128, but allow some room
1008 m_compLimitMembers = 0; // probably ok, and AFAIK doesn't support anon structs
1009 m_compLimitParens = 80; // 128, but allow some room
1010 } else {
1011 fl->v3fatal("Unknown setting for --compiler: '"
1012 << valp << "'\n"
1013 << fl->warnMore() << "... Suggest 'clang', 'gcc', or 'msvc'");
1014 }
1015 });
1016 DECL_OPTION("-coverage", CbOnOff, [this](bool flag) { coverage(flag); });
1017 DECL_OPTION("-converge-limit", Set, &m_convergeLimit);
1018 DECL_OPTION("-coverage-line", OnOff, &m_coverageLine);
1019 DECL_OPTION("-coverage-max-width", Set, &m_coverageMaxWidth);
1020 DECL_OPTION("-coverage-toggle", OnOff, &m_coverageToggle);
1021 DECL_OPTION("-coverage-underscore", OnOff, &m_coverageUnderscore);
1022 DECL_OPTION("-coverage-user", OnOff, &m_coverageUser);
1023
1024 DECL_OPTION("-D", CbPartialMatch, [this](const char* valp) { addDefine(valp, false); });
1025 DECL_OPTION("-debug", CbCall, [this]() { setDebugMode(3); });
1026 DECL_OPTION("-debugi", CbVal, [this](int v) { setDebugMode(v); });
1027 DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
1028 setDebugSrcLevel(optp, std::atoi(valp));
1029 });
1030 DECL_OPTION("-debug-abort", CbCall,
1031 V3Error::vlAbort)
1032 .undocumented(); // See also --debug-sigsegv
1033 DECL_OPTION("-debug-check", OnOff, &m_debugCheck);
1034 DECL_OPTION("-debug-collision", OnOff, &m_debugCollision).undocumented();
1035 DECL_OPTION("-debug-emitv", OnOff, &m_debugEmitV).undocumented();
1036 DECL_OPTION("-debug-exit-parse", OnOff, &m_debugExitParse).undocumented();
1037 DECL_OPTION("-debug-exit-uvm", OnOff, &m_debugExitUvm).undocumented();
1038 DECL_OPTION("-debug-fatalsrc", CbCall, []() {
1039 v3fatalSrc("--debug-fatal-src");
1040 }).undocumented(); // See also --debug-abort
1041 DECL_OPTION("-debug-leak", OnOff, &m_debugLeak);
1042 DECL_OPTION("-debug-nondeterminism", OnOff, &m_debugNondeterminism);
1043 DECL_OPTION("-debug-partition", OnOff, &m_debugPartition).undocumented();
1044 DECL_OPTION("-debug-protect", OnOff, &m_debugProtect).undocumented();
1045 DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented();
1046 DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort
1047 DECL_OPTION("-decoration", OnOff, &m_decoration);
1048 DECL_OPTION("-dpi-hdr-only", OnOff, &m_dpiHdrOnly);
1049 DECL_OPTION("-dump-defines", OnOff, &m_dumpDefines);
1050 DECL_OPTION("-dump-tree", CbOnOff,
1051 [this](bool flag) { m_dumpTree = flag ? 3 : 0; }); // Also see --dump-treei
1052 DECL_OPTION("-dump-tree-addrids", OnOff, &m_dumpTreeAddrids);
1053 DECL_OPTION("-dump-treei", Set, &m_dumpTree);
1054 DECL_OPTION("-dump-treei-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
1055 setDumpTreeLevel(optp, std::atoi(valp));
1056 });
1057
1058 DECL_OPTION("-E", Set, &m_preprocOnly);
1059 DECL_OPTION("-error-limit", CbVal, static_cast<void (*)(int)>(&V3Error::errorLimit));
1060 DECL_OPTION("-exe", OnOff, &m_exe);
1061 DECL_OPTION("-expand-limit", CbVal,
1062 [this](const char* valp) { m_expandLimit = std::atoi(valp); });
1063
1064 DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) {
1065 parseOptsFile(fl, parseFileArg(optdir, valp), true);
1066 });
1067 DECL_OPTION("-FI", CbVal,
1068 [this, &optdir](const char* valp) { addForceInc(parseFileArg(optdir, valp)); });
1069 DECL_OPTION("-f", CbVal, [this, fl, &optdir](const char* valp) {
1070 parseOptsFile(fl, parseFileArg(optdir, valp), false);
1071 });
1072 DECL_OPTION("-flatten", OnOff, &m_flatten);
1073
1074 DECL_OPTION("-G", CbPartialMatch, [this](const char* optp) { addParameter(optp, false); });
1075 DECL_OPTION("-gate-stmts", Set, &m_gateStmts);
1076 DECL_OPTION("-gdb", CbCall, []() {}); // Processed only in bin/verilator shell
1077 DECL_OPTION("-gdbbt", CbCall, []() {}); // Processed only in bin/verilator shell
1078 DECL_OPTION("-generate-key", CbCall, [this]() {
1079 cout << protectKeyDefaulted() << endl;
1080 std::exit(0);
1081 });
1082 DECL_OPTION("-getenv", CbVal, [](const char* valp) {
1083 cout << V3Options::getenvBuiltins(valp) << endl;
1084 std::exit(0);
1085 });
1086
1087 DECL_OPTION("-hierarchical", OnOff, &m_hierarchical);
1088 DECL_OPTION("-hierarchical-block", CbVal, [this](const char* valp) {
1089 const V3HierarchicalBlockOption opt(valp);
1090 m_hierBlocks.emplace(opt.mangledName(), opt);
1091 });
1092 DECL_OPTION("-hierarchical-child", OnOff, &m_hierChild);
1093
1094 DECL_OPTION("-I", CbPartialMatch,
1095 [this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); });
1096 DECL_OPTION("-if-depth", Set, &m_ifDepth);
1097 DECL_OPTION("-ignc", OnOff, &m_ignc);
1098 DECL_OPTION("-inline-mult", Set, &m_inlineMult);
1099 DECL_OPTION("-instr-count-dpi", CbVal, [this, fl](int val) {
1100 m_instrCountDpi = val;
1101 if (m_instrCountDpi < 0) fl->v3fatal("--instr-count-dpi must be non-negative: " << val);
1102 });
1103
1104 DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs));
1105 const auto setLang = [this, fl](const char* valp) {
1106 const V3LangCode optval = V3LangCode(valp);
1107 if (optval.legal()) {
1108 m_defaultLanguage = optval;
1109 } else {
1110 VSpellCheck spell;
1111 for (int i = V3LangCode::L_ERROR + 1; i < V3LangCode::_ENUM_END; ++i) {
1112 spell.pushCandidate(V3LangCode{i}.ascii());
1113 }
1114 fl->v3fatal("Unknown language specified: " << valp << spell.bestCandidateMsg(valp));
1115 }
1116 };
1117 DECL_OPTION("-default-language", CbVal, setLang);
1118 DECL_OPTION("-language", CbVal, setLang);
1119 DECL_OPTION("-lib-create", Set, &m_libCreate);
1120 DECL_OPTION("-lint-only", OnOff, &m_lintOnly);
1121 DECL_OPTION("-l2-name", Set, &m_l2Name);
1122 DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical
1123 DECL_OPTION("-l2name", CbCall, [this]() { m_l2Name = "v"; }).undocumented(); // Historical
1124
1125 DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags));
1126 DECL_OPTION("-MMD", OnOff, &m_makeDepend);
1127 DECL_OPTION("-MP", OnOff, &m_makePhony);
1128 DECL_OPTION("-Mdir", CbVal, [this](const char* valp) {
1129 m_makeDir = valp;
1130 addIncDirFallback(m_makeDir); // Need to find generated files there too
1131 });
1132 DECL_OPTION("-main", OnOff, &m_main).undocumented(); // Future
1133 DECL_OPTION("-make", CbVal, [this, fl](const char* valp) {
1134 if (!strcmp(valp, "cmake")) {
1135 m_cmake = true;
1136 } else if (!strcmp(valp, "gmake")) {
1137 m_gmake = true;
1138 } else {
1139 fl->v3fatal("Unknown --make system specified: '" << valp << "'");
1140 }
1141 });
1142 DECL_OPTION("-max-num-width", Set, &m_maxNumWidth);
1143 DECL_OPTION("-merge-const-pool", OnOff, &m_mergeConstPool);
1144 DECL_OPTION("-mod-prefix", Set, &m_modPrefix);
1145
1146 DECL_OPTION("-O", CbPartialMatch, [this](const char* optp) {
1147 // Optimization
1148 for (const char* cp = optp; *cp; ++cp) {
1149 const bool flag = isupper(*cp);
1150 switch (tolower(*cp)) {
1151 case '0': optimize(0); break; // 0=all off
1152 case '1': optimize(1); break; // 1=all on
1153 case '2': optimize(2); break; // 2=not used
1154 case '3': optimize(3); break; // 3=high
1155 case 'a': m_oTable = flag; break;
1156 case 'b': m_oCombine = flag; break;
1157 case 'c': m_oConst = flag; break;
1158 case 'd': m_oDedupe = flag; break;
1159 case 'e': m_oCase = flag; break;
1160 // f
1161 case 'g': m_oGate = flag; break;
1162 // h
1163 case 'i': m_oInline = flag; break;
1164 // j
1165 case 'k': m_oSubstConst = flag; break;
1166 case 'l': m_oLife = flag; break;
1167 case 'm': m_oAssemble = flag; break;
1168 // n
1169 case 'o': m_oConstBitOpTree = flag; break; // Can remove ~2022-01 when stable
1170 case 'p':
1171 m_public = !flag;
1172 break; // With -Op so flag=0, we want public on so few optimizations done
1173 // q
1174 case 'r': m_oReorder = flag; break;
1175 case 's': m_oSplit = flag; break;
1176 case 't': m_oLifePost = flag; break;
1177 case 'u': m_oSubst = flag; break;
1178 case 'v': m_oReloop = flag; break;
1179 case 'w': m_oMergeCond = flag; break;
1180 case 'x': m_oExpand = flag; break;
1181 case 'y': m_oAcycSimp = flag; break;
1182 case 'z': m_oLocalize = flag; break;
1183 default: break; // No error, just ignore
1184 }
1185 }
1186 });
1187 DECL_OPTION("-o", Set, &m_exeName);
1188 DECL_OPTION("-order-clock-delay", OnOff, &m_orderClockDly);
1189 DECL_OPTION("-output-split", Set, &m_outputSplit);
1190 DECL_OPTION("-output-split-cfuncs", CbVal, [this, fl](const char* valp) {
1191 m_outputSplitCFuncs = std::atoi(valp);
1192 if (m_outputSplitCFuncs < 0) {
1193 fl->v3error("--output-split-cfuncs must be >= 0: " << valp);
1194 }
1195 });
1196 DECL_OPTION("-output-split-ctrace", CbVal, [this, fl](const char* valp) {
1197 m_outputSplitCTrace = std::atoi(valp);
1198 if (m_outputSplitCTrace < 0) {
1199 fl->v3error("--output-split-ctrace must be >= 0: " << valp);
1200 }
1201 });
1202
1203 DECL_OPTION("-P", Set, &m_preprocNoLine);
1204 DECL_OPTION("-pvalue+", CbPartialMatch,
1205 [this](const char* varp) { addParameter(varp, false); });
1206 DECL_OPTION("-pins64", CbCall, [this]() { m_pinsBv = 65; });
1207 DECL_OPTION("-no-pins64", CbCall, [this]() { m_pinsBv = 33; });
1208 DECL_OPTION("-pins-bv", CbVal, [this, fl](const char* valp) {
1209 m_pinsBv = std::atoi(valp);
1210 if (m_pinsBv > 65) fl->v3fatal("--pins-bv maximum is 65: " << valp);
1211 });
1212 DECL_OPTION("-pins-sc-uint", CbOnOff, [this](bool flag) {
1213 m_pinsScUint = flag;
1214 if (!m_pinsScBigUint) m_pinsBv = 65;
1215 });
1216 DECL_OPTION("-pins-sc-biguint", CbOnOff, [this](bool flag) {
1217 m_pinsScBigUint = flag;
1218 m_pinsBv = 513;
1219 });
1220 DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8);
1221 DECL_OPTION("-pipe-filter", Set, &m_pipeFilter);
1222 DECL_OPTION("-pp-comments", OnOff, &m_ppComments);
1223 DECL_OPTION("-prefix", CbVal, [this](const char* valp) {
1224 m_prefix = valp;
1225 if (m_modPrefix == "") m_modPrefix = m_prefix;
1226 });
1227 DECL_OPTION("-private", CbCall, [this]() { m_public = false; });
1228 DECL_OPTION("-prof-c", OnOff, &m_profC);
1229 DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; });
1230 DECL_OPTION("-profile-cfuncs", CbCall,
1231 [this]() { m_profC = m_profCFuncs = true; }); // Renamed
1232 DECL_OPTION("-prof-threads", OnOff, &m_profThreads);
1233 DECL_OPTION("-protect-ids", OnOff, &m_protectIds);
1234 DECL_OPTION("-protect-key", Set, &m_protectKey);
1235 DECL_OPTION("-protect-lib", CbVal, [this](const char* valp) {
1236 m_libCreate = valp;
1237 m_protectIds = true;
1238 });
1239 DECL_OPTION("-public", OnOff, &m_public);
1240 DECL_OPTION("-public-flat-rw", CbOnOff, [this](bool flag) {
1241 m_publicFlatRW = flag;
1242 v3Global.dpi(true);
1243 });
1244
1245 DECL_OPTION("-quiet-exit", OnOff, &m_quietExit);
1246
1247 DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes);
1248 DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) {
1249 m_reloopLimit = std::atoi(valp);
1250 if (m_reloopLimit < 2) { fl->v3error("--reloop-limit must be >= 2: " << valp); }
1251 });
1252 DECL_OPTION("-report-unoptflat", OnOff, &m_reportUnoptflat);
1253 DECL_OPTION("-rr", CbCall, []() {}); // Processed only in bin/verilator shell
1254
1255 DECL_OPTION("-savable", OnOff, &m_savable);
1256 DECL_OPTION("-sc", CbCall, [this]() {
1257 m_outFormatOk = true;
1258 m_systemC = true;
1259 });
1260 DECL_OPTION("-skip-identical", OnOff, &m_skipIdentical);
1261 DECL_OPTION("-stats", OnOff, &m_stats);
1262 DECL_OPTION("-stats-vars", CbOnOff, [this](bool flag) {
1263 m_statsVars = flag;
1264 m_stats |= flag;
1265 });
1266 DECL_OPTION("-structs-unpacked", OnOff, &m_structsPacked);
1267 DECL_OPTION("-sv", CbCall, [this]() { m_defaultLanguage = V3LangCode::L1800_2017; });
1268
1269 DECL_OPTION("-threads-coarsen", OnOff, &m_threadsCoarsen).undocumented(); // Debug
1270 DECL_OPTION("-no-threads", CbCall, [this]() { m_threads = 0; });
1271 DECL_OPTION("-threads", CbVal, [this, fl](const char* valp) {
1272 m_threads = std::atoi(valp);
1273 if (m_threads < 0) fl->v3fatal("--threads must be >= 0: " << valp);
1274 });
1275 DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) {
1276 if (!strcmp(valp, "all")) {
1277 m_threadsDpiPure = true;
1278 m_threadsDpiUnpure = true;
1279 } else if (!strcmp(valp, "none")) {
1280 m_threadsDpiPure = false;
1281 m_threadsDpiUnpure = false;
1282 } else if (!strcmp(valp, "pure")) {
1283 m_threadsDpiPure = true;
1284 m_threadsDpiUnpure = false;
1285 } else {
1286 fl->v3fatal("Unknown setting for --threads-dpi: '"
1287 << valp << "'\n"
1288 << fl->warnMore() << "... Suggest 'all', 'none', or 'pure'");
1289 }
1290 });
1291 DECL_OPTION("-threads-max-mtasks", CbVal, [this, fl](const char* valp) {
1292 m_threadsMaxMTasks = std::atoi(valp);
1293 if (m_threadsMaxMTasks < 1) fl->v3fatal("--threads-max-mtasks must be >= 1: " << valp);
1294 });
1295 DECL_OPTION("-timescale", CbVal, [this, fl](const char* valp) {
1296 VTimescale unit;
1297 VTimescale prec;
1298 VTimescale::parseSlashed(fl, valp, unit /*ref*/, prec /*ref*/);
1299 if (!unit.isNone() && timeOverrideUnit().isNone()) m_timeDefaultUnit = unit;
1300 if (!prec.isNone() && timeOverridePrec().isNone()) m_timeDefaultPrec = prec;
1301 });
1302 DECL_OPTION("-timescale-override", CbVal, [this, fl](const char* valp) {
1303 VTimescale unit;
1304 VTimescale prec;
1305 VTimescale::parseSlashed(fl, valp, unit /*ref*/, prec /*ref*/, true);
1306 if (!unit.isNone()) {
1307 m_timeDefaultUnit = unit;
1308 m_timeOverrideUnit = unit;
1309 }
1310 if (!prec.isNone()) {
1311 m_timeDefaultPrec = prec;
1312 m_timeOverridePrec = prec;
1313 }
1314 });
1315 DECL_OPTION("-top-module", Set, &m_topModule);
1316 DECL_OPTION("-top", Set, &m_topModule);
1317 DECL_OPTION("-trace", OnOff, &m_trace);
1318 DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage);
1319 DECL_OPTION("-trace-depth", Set, &m_traceDepth);
1320 DECL_OPTION("-trace-fst", CbCall, [this]() {
1321 m_trace = true;
1322 m_traceFormat = TraceFormat::FST;
1323 addLdLibs("-lz");
1324 });
1325 DECL_OPTION("-trace-fst-thread", CbCall, [this, fl]() {
1326 m_trace = true;
1327 m_traceFormat = TraceFormat::FST;
1328 addLdLibs("-lz");
1329 fl->v3warn(DEPRECATED, "Option --trace-fst-thread is deprecated. "
1330 "Use --trace-fst with --trace-threads > 0.");
1331 if (m_traceThreads == 0) m_traceThreads = 1;
1332 });
1333 DECL_OPTION("-trace-max-array", Set, &m_traceMaxArray);
1334 DECL_OPTION("-trace-max-width", Set, &m_traceMaxWidth);
1335 DECL_OPTION("-trace-params", OnOff, &m_traceParams);
1336 DECL_OPTION("-trace-structs", OnOff, &m_traceStructs);
1337 DECL_OPTION("-trace-threads", CbVal, [this, fl](const char* valp) {
1338 m_trace = true;
1339 m_traceThreads = std::atoi(valp);
1340 if (m_traceThreads < 0) fl->v3fatal("--trace-threads must be >= 0: " << valp);
1341 });
1342 DECL_OPTION("-trace-underscore", OnOff, &m_traceUnderscore);
1343
1344 DECL_OPTION("-U", CbPartialMatch, &V3PreShell::undef);
1345 DECL_OPTION("-underline-zero", OnOff, &m_underlineZero); // Deprecated
1346 DECL_OPTION("-unroll-count", Set, &m_unrollCount).undocumented(); // Optimization tweak
1347 DECL_OPTION("-unroll-stmts", Set, &m_unrollStmts).undocumented(); // Optimization tweak
1348 DECL_OPTION("-unused-regexp", Set, &m_unusedRegexp);
1349
1350 DECL_OPTION("-V", CbCall, [this]() {
1351 showVersion(true);
1352 std::exit(0);
1353 });
1354 DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) {
1355 V3Options::addLibraryFile(parseFileArg(optdir, valp));
1356 });
1357 DECL_OPTION("-verilate", OnOff, &m_verilate);
1358 DECL_OPTION("-version", CbCall, [this]() {
1359 showVersion(false);
1360 std::exit(0);
1361 });
1362 DECL_OPTION("-vpi", OnOff, &m_vpi);
1363
1364 DECL_OPTION("-Wpedantic", OnOff, &m_pedantic);
1365 DECL_OPTION("-Wall", CbCall, []() {
1366 FileLine::globalWarnLintOff(false);
1367 FileLine::globalWarnStyleOff(false);
1368 });
1369 DECL_OPTION("-Werror-", CbPartialMatch, [this, fl](const char* optp) {
1370 const V3ErrorCode code(optp);
1371 if (code == V3ErrorCode::EC_ERROR) {
1372 if (!isFuture(optp)) fl->v3fatal("Unknown warning specified: -Werror-" << optp);
1373 } else {
1374 V3Error::pretendError(code, true);
1375 }
1376 });
1377 DECL_OPTION("-Wfuture-", CbPartialMatch, [this](const char* optp) {
1378 // Note it may not be a future option, but one that is currently implemented.
1379 addFuture(optp);
1380 });
1381 DECL_OPTION("-Wno-", CbPartialMatch, [fl, &parser](const char* optp) {
1382 if (!FileLine::globalWarnOff(optp, true)) {
1383 const string fullopt = string{"-Wno-"} + optp;
1384 fl->v3fatal("Unknown warning specified: " << fullopt
1385 << parser.getSuggestion(fullopt.c_str()));
1386 }
1387 });
1388 for (int i = V3ErrorCode::EC_FIRST_WARN; i < V3ErrorCode::_ENUM_MAX; ++i) {
1389 for (const string prefix : {"-Wno-", "-Wwarn-"})
1390 parser.addSuggestionCandidate(prefix + V3ErrorCode{i}.ascii());
1391 }
1392 DECL_OPTION("-Wno-context", CbCall, [this]() { m_context = false; });
1393 DECL_OPTION("-Wno-fatal", CbCall, []() { V3Error::warnFatal(false); });
1394 DECL_OPTION("-Wno-lint", CbCall, []() {
1395 FileLine::globalWarnLintOff(true);
1396 FileLine::globalWarnStyleOff(true);
1397 });
1398 DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); });
1399 DECL_OPTION("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) {
1400 const V3ErrorCode code{optp};
1401 if (code == V3ErrorCode::EC_ERROR) {
1402 if (!isFuture(optp)) {
1403 const string fullopt = string{"-Wwarn-"} + optp;
1404 fl->v3fatal("Unknown warning specified: "
1405 << fullopt << parser.getSuggestion(fullopt.c_str()));
1406 }
1407 } else {
1408 FileLine::globalWarnOff(code, false);
1409 V3Error::pretendError(code, false);
1410 }
1411 });
1412 DECL_OPTION("-Wwarn-lint", CbCall, []() { FileLine::globalWarnLintOff(false); });
1413 DECL_OPTION("-Wwarn-style", CbCall, []() { FileLine::globalWarnStyleOff(false); });
1414 DECL_OPTION("-waiver-output", Set, &m_waiverOutput);
1415
1416 DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) {
1417 if (!strcmp(valp, "0")) {
1418 m_xAssign = "0";
1419 } else if (!strcmp(valp, "1")) {
1420 m_xAssign = "1";
1421 } else if (!strcmp(valp, "fast")) {
1422 m_xAssign = "fast";
1423 } else if (!strcmp(valp, "unique")) {
1424 m_xAssign = "unique";
1425 } else {
1426 fl->v3fatal("Unknown setting for --x-assign: '"
1427 << valp << "'\n"
1428 << fl->warnMore() << "... Suggest '0', '1', 'fast', or 'unique'");
1429 }
1430 });
1431 DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) {
1432 if (!strcmp(valp, "0")) {
1433 m_xInitial = "0";
1434 } else if (!strcmp(valp, "fast")) {
1435 m_xInitial = "fast";
1436 } else if (!strcmp(valp, "unique")) {
1437 m_xInitial = "unique";
1438 } else {
1439 fl->v3fatal("Unknown setting for --x-initial: '"
1440 << valp << "'\n"
1441 << fl->warnMore() << "... Suggest '0', 'fast', or 'unique'");
1442 }
1443 });
1444 DECL_OPTION("-x-initial-edge", OnOff, &m_xInitialEdge);
1445 DECL_OPTION("-xml-only", OnOff, &m_xmlOnly);
1446 DECL_OPTION("-xml-output", CbVal, [this](const char* valp) {
1447 m_xmlOutput = valp;
1448 m_xmlOnly = true;
1449 });
1450
1451 DECL_OPTION("-y", CbVal, [this, &optdir](const char* valp) {
1452 addIncDirUser(parseFileArg(optdir, string(valp)));
1453 });
1454 parser.finalize();
1455
1456 for (int i = 0; i < argc;) {
1457 UINFO(9, " Option: " << argv[i] << endl);
1458 if (!strcmp(argv[i], "-j") || !strcmp(argv[i], "--j")) { // Allow gnu -- switches
1459 ++i;
1460 m_buildJobs = 0; // Unlimited parallelism
1461 if (i < argc && isdigit(argv[i][0])) {
1462 m_buildJobs = atoi(argv[i]);
1463 if (m_buildJobs <= 0) {
1464 fl->v3error("-j accepts positive integer, but '" << argv[i] << "' is passed");
1465 }
1466 ++i;
1467 }
1468 } else if (argv[i][0] == '-' || argv[i][0] == '+') {
1469 if (const int consumed = parser.parse(i, argc, argv)) {
1470 i += consumed;
1471 } else {
1472 fl->v3fatal("Invalid option: " << argv[i] << parser.getSuggestion(argv[i]));
1473 ++i; // LCOV_EXCL_LINE
1474 }
1475 } else {
1476 // Filename
1477 const string filename = parseFileArg(optdir, argv[i]);
1478 if (suffixed(filename, ".cpp") //
1479 || suffixed(filename, ".cxx") //
1480 || suffixed(filename, ".cc") //
1481 || suffixed(filename, ".c") //
1482 || suffixed(filename, ".sp")) {
1483 V3Options::addCppFile(filename);
1484 } else if (suffixed(filename, ".a") //
1485 || suffixed(filename, ".o") //
1486 || suffixed(filename, ".so")) {
1487 V3Options::addLdLibs(filename);
1488 } else {
1489 V3Options::addVFile(filename);
1490 }
1491 ++i;
1492 }
1493 }
1494 }
1495
1496 //======================================================================
1497
parseOptsFile(FileLine * fl,const string & filename,bool rel)1498 void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
1499 // Read the specified -f filename and process as arguments
1500 UINFO(1, "Reading Options File " << filename << endl);
1501
1502 const std::unique_ptr<std::ifstream> ifp{V3File::new_ifstream(filename)};
1503 if (ifp->fail()) {
1504 fl->v3error("Cannot open -f command file: " + filename);
1505 return;
1506 }
1507
1508 string whole_file;
1509 bool inCmt = false;
1510 while (!ifp->eof()) {
1511 const string line = V3Os::getline(*ifp);
1512 // Strip simple comments
1513 string oline;
1514 // cppcheck-suppress StlMissingComparison
1515 char lastch = ' ';
1516 bool space_begin = true; // At beginning or leading spaces only
1517 for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) {
1518 if (inCmt) {
1519 if (*pos == '*' && *(pos + 1) == '/') {
1520 inCmt = false;
1521 ++pos;
1522 }
1523 } else if (*pos == '/' && *(pos + 1) == '/'
1524 && (pos == line.begin() || isspace(lastch))) { // But allow /file//path
1525 break; // Ignore to EOL
1526 } else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line
1527 break; // Ignore to EOL
1528 } else if (*pos == '/' && *(pos + 1) == '*') {
1529 inCmt = true;
1530 space_begin = false;
1531 // cppcheck-suppress StlMissingComparison
1532 ++pos;
1533 } else {
1534 if (!isspace(*pos)) space_begin = false;
1535 oline += *pos;
1536 }
1537 }
1538 whole_file += oline + " ";
1539 }
1540 whole_file += "\n"; // So string match below is simplified
1541 if (inCmt) fl->v3error("Unterminated /* comment inside -f file.");
1542
1543 fl = new FileLine(filename);
1544
1545 // Split into argument list and process
1546 // Note we try to respect escaped char, double/simple quoted strings
1547 // Other simulators don't respect a common syntax...
1548
1549 // Strip off arguments and parse into words
1550 std::vector<string> args;
1551
1552 // Parse file using a state machine, taking into account quoted strings and escaped chars
1553 enum state : uint8_t {
1554 ST_IN_OPTION,
1555 ST_ESCAPED_CHAR,
1556 ST_IN_QUOTED_STR,
1557 ST_IN_DOUBLE_QUOTED_STR
1558 };
1559
1560 state st = ST_IN_OPTION;
1561 state last_st = ST_IN_OPTION;
1562 string arg;
1563 for (string::size_type pos = 0; pos < whole_file.length(); ++pos) {
1564 char curr_char = whole_file[pos];
1565 switch (st) {
1566 case ST_IN_OPTION: // Get all chars up to a white space or a "="
1567 if (isspace(curr_char)) { // End of option
1568 if (!arg.empty()) { // End of word
1569 args.push_back(arg);
1570 }
1571 arg = "";
1572 break;
1573 }
1574 if (curr_char == '\\') { // Escape char, we wait for next char
1575 last_st = st; // Memorize current state
1576 st = ST_ESCAPED_CHAR;
1577 break;
1578 }
1579 if (curr_char == '\'') { // Find begin of quoted string
1580 // Examine next char in order to decide between
1581 // a string or a base specifier for integer literal
1582 ++pos;
1583 if (pos < whole_file.length()) curr_char = whole_file[pos];
1584 if (curr_char == '"') { // String
1585 st = ST_IN_QUOTED_STR;
1586 } else { // Base specifier
1587 arg += '\'';
1588 }
1589 arg += curr_char;
1590 break;
1591 }
1592 if (curr_char == '"') { // Find begin of double quoted string
1593 // Doesn't insert the quote
1594 st = ST_IN_DOUBLE_QUOTED_STR;
1595 break;
1596 }
1597 arg += curr_char;
1598 break;
1599 case ST_IN_QUOTED_STR: // Just store all chars inside string
1600 if (curr_char != '\'') {
1601 arg += curr_char;
1602 } else { // End of quoted string
1603 st = ST_IN_OPTION;
1604 }
1605 break;
1606 case ST_IN_DOUBLE_QUOTED_STR: // Take into account escaped chars
1607 if (curr_char != '"') {
1608 if (curr_char == '\\') {
1609 last_st = st;
1610 st = ST_ESCAPED_CHAR;
1611 } else {
1612 arg += curr_char;
1613 }
1614 } else { // End of double quoted string
1615 st = ST_IN_OPTION;
1616 }
1617 break;
1618 case ST_ESCAPED_CHAR: // Just add the escaped char
1619 arg += curr_char;
1620 st = last_st;
1621 break;
1622 }
1623 }
1624 if (!arg.empty()) { // Add last word
1625 args.push_back(arg);
1626 }
1627
1628 // Path
1629 const string optdir = (rel ? V3Os::filenameDir(filename) : ".");
1630
1631 // Convert to argv style arg list and parse them
1632 std::vector<char*> argv;
1633 argv.reserve(args.size() + 1);
1634 for (const string& i : args) argv.push_back(const_cast<char*>(i.c_str()));
1635 argv.push_back(nullptr); // argv is nullptr-terminated
1636 parseOptsList(fl, optdir, static_cast<int>(argv.size() - 1), argv.data());
1637 }
1638
1639 //======================================================================
1640
parseFileArg(const string & optdir,const string & relfilename)1641 string V3Options::parseFileArg(const string& optdir, const string& relfilename) {
1642 string filename = V3Os::filenameSubstitute(relfilename);
1643 if (optdir != "." && V3Os::filenameIsRel(filename)) filename = optdir + "/" + filename;
1644 return filename;
1645 }
1646
1647 //======================================================================
1648
showVersion(bool verbose)1649 void V3Options::showVersion(bool verbose) {
1650 cout << version();
1651 cout << endl;
1652 if (!verbose) return;
1653
1654 cout << endl;
1655 cout << "Copyright 2003-2021 by Wilson Snyder. Verilator is free software; you can\n";
1656 cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
1657 cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
1658 cout << "License Version 2.0.\n";
1659
1660 cout << endl;
1661 cout << "See https://verilator.org for documentation\n";
1662
1663 cout << endl;
1664 cout << "Summary of configuration:\n";
1665 cout << " Compiled in defaults if not in environment:\n";
1666 cout << " SYSTEMC = " << DEFENV_SYSTEMC << endl;
1667 cout << " SYSTEMC_ARCH = " << DEFENV_SYSTEMC_ARCH << endl;
1668 cout << " SYSTEMC_INCLUDE = " << DEFENV_SYSTEMC_INCLUDE << endl;
1669 cout << " SYSTEMC_LIBDIR = " << DEFENV_SYSTEMC_LIBDIR << endl;
1670 cout << " VERILATOR_ROOT = " << DEFENV_VERILATOR_ROOT << endl;
1671 cout << " SystemC system-wide = " << cvtToStr(systemCSystemWide()) << endl;
1672
1673 cout << endl;
1674 cout << "Environment:\n";
1675 cout << " MAKE = " << V3Os::getenvStr("MAKE", "") << endl;
1676 cout << " PERL = " << V3Os::getenvStr("PERL", "") << endl;
1677 cout << " SYSTEMC = " << V3Os::getenvStr("SYSTEMC", "") << endl;
1678 cout << " SYSTEMC_ARCH = " << V3Os::getenvStr("SYSTEMC_ARCH", "") << endl;
1679 cout << " SYSTEMC_INCLUDE = " << V3Os::getenvStr("SYSTEMC_INCLUDE", "") << endl;
1680 cout << " SYSTEMC_LIBDIR = " << V3Os::getenvStr("SYSTEMC_LIBDIR", "") << endl;
1681 cout << " VERILATOR_ROOT = " << V3Os::getenvStr("VERILATOR_ROOT", "") << endl;
1682 // wrapper uses this:
1683 cout << " VERILATOR_BIN = " << V3Os::getenvStr("VERILATOR_BIN", "") << endl;
1684
1685 cout << endl;
1686 cout << "Features (based on environment or compiled-in support):\n";
1687 cout << " SystemC found = " << cvtToStr(systemCFound()) << endl;
1688 }
1689
1690 //======================================================================
1691
V3Options()1692 V3Options::V3Options() {
1693 m_impp = new V3OptionsImp;
1694
1695 m_traceFormat = TraceFormat::VCD;
1696
1697 m_makeDir = "obj_dir";
1698 m_unusedRegexp = "*unused*";
1699 m_xAssign = "fast";
1700
1701 m_defaultLanguage = V3LangCode::mostRecent();
1702
1703 VName::maxLength(128); // Linux filename limits 256; leave half for prefix
1704
1705 optimize(1);
1706 // Default +libext+
1707 addLibExtV(""); // So include "filename.v" will find the same file
1708 addLibExtV(".v");
1709 addLibExtV(".sv");
1710 // Default -I
1711 addIncDirFallback("."); // Looks better than {long_cwd_path}/...
1712 }
1713
~V3Options()1714 V3Options::~V3Options() { VL_DO_CLEAR(delete m_impp, m_impp = nullptr); }
1715
setDebugMode(int level)1716 void V3Options::setDebugMode(int level) {
1717 V3Error::debugDefault(level);
1718 if (!m_dumpTree) m_dumpTree = 3; // Don't override if already set.
1719 m_stats = true;
1720 m_debugCheck = true;
1721 cout << "Starting " << version() << endl;
1722 }
1723
setDebugSrcLevel(const string & srcfile,int level)1724 void V3Options::setDebugSrcLevel(const string& srcfile, int level) {
1725 const auto iter = m_debugSrcs.find(srcfile);
1726 if (iter != m_debugSrcs.end()) {
1727 iter->second = level;
1728 } else {
1729 m_debugSrcs.emplace(srcfile, level);
1730 }
1731 }
1732
debugSrcLevel(const string & srcfile_path,int default_level)1733 int V3Options::debugSrcLevel(const string& srcfile_path, int default_level) {
1734 // For simplicity, calling functions can just use __FILE__ for srcfile.
1735 // That means though we need to cleanup the filename from ../Foo.cpp -> Foo
1736 const string srcfile = V3Os::filenameNonDirExt(srcfile_path);
1737 const auto iter = m_debugSrcs.find(srcfile);
1738 if (iter != m_debugSrcs.end()) {
1739 return iter->second;
1740 } else {
1741 return default_level;
1742 }
1743 }
1744
setDumpTreeLevel(const string & srcfile,int level)1745 void V3Options::setDumpTreeLevel(const string& srcfile, int level) {
1746 const auto iter = m_dumpTrees.find(srcfile);
1747 if (iter != m_dumpTrees.end()) {
1748 iter->second = level;
1749 } else {
1750 m_dumpTrees.emplace(srcfile, level);
1751 }
1752 }
1753
dumpTreeLevel(const string & srcfile_path)1754 int V3Options::dumpTreeLevel(const string& srcfile_path) {
1755 // For simplicity, calling functions can just use __FILE__ for srcfile.
1756 // That means though we need to cleanup the filename from ../Foo.cpp -> Foo
1757 const string srcfile = V3Os::filenameNonDirExt(srcfile_path);
1758 const auto iter = m_dumpTrees.find(srcfile);
1759 if (iter != m_dumpTrees.end()) {
1760 return iter->second;
1761 } else {
1762 return m_dumpTree;
1763 }
1764 }
1765
optimize(int level)1766 void V3Options::optimize(int level) {
1767 // Set all optimizations to on/off
1768 const bool flag = level > 0;
1769 m_oAcycSimp = flag;
1770 m_oAssemble = flag;
1771 m_oCase = flag;
1772 m_oCombine = flag;
1773 m_oConst = flag;
1774 m_oConstBitOpTree = flag;
1775 m_oDedupe = flag;
1776 m_oExpand = flag;
1777 m_oGate = flag;
1778 m_oInline = flag;
1779 m_oLife = flag;
1780 m_oLifePost = flag;
1781 m_oLocalize = flag;
1782 m_oMergeCond = flag;
1783 m_oReloop = flag;
1784 m_oReorder = flag;
1785 m_oSplit = flag;
1786 m_oSubst = flag;
1787 m_oSubstConst = flag;
1788 m_oTable = flag;
1789 // And set specific optimization levels
1790 if (level >= 3) {
1791 m_inlineMult = -1; // Maximum inlining
1792 }
1793 }
1794