2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Options parsing
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2022-01-01 14:26:40 +01:00
|
|
|
// Copyright 2003-2022 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
|
|
|
|
#include "V3Options.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
|
|
|
|
|
#include "V3Ast.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3Error.h"
|
|
|
|
|
#include "V3File.h"
|
2022-08-05 11:56:57 +02:00
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3OptionParser.h"
|
|
|
|
|
#include "V3Os.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
#include "V3PreShell.h"
|
2021-03-26 14:48:24 +01:00
|
|
|
#include "V3String.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format off
|
2006-08-26 13:35:28 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
2010-02-01 15:28:53 +01:00
|
|
|
#ifndef _WIN32
|
2010-02-01 12:41:17 +01:00
|
|
|
# include <sys/utsname.h>
|
2009-11-13 17:08:30 +01:00
|
|
|
#endif
|
2020-04-16 01:39:03 +02:00
|
|
|
#include <algorithm>
|
2008-05-28 21:58:18 +02:00
|
|
|
#include <cctype>
|
2006-08-26 13:35:28 +02:00
|
|
|
#include <dirent.h>
|
2013-02-05 03:21:55 +01:00
|
|
|
#include <fcntl.h>
|
2006-08-26 13:35:28 +02:00
|
|
|
#include <list>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <memory>
|
2022-09-15 14:28:58 +02:00
|
|
|
#include <thread>
|
2018-10-14 13:04:18 +02:00
|
|
|
#include <set>
|
2022-09-18 21:53:42 +02:00
|
|
|
#include <string>
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "config_rev.h"
|
|
|
|
|
|
2019-12-28 17:44:24 +01:00
|
|
|
#if defined(_WIN32) || defined(__MINGW32__)
|
|
|
|
|
# include <io.h> // open, close
|
|
|
|
|
#endif
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format on
|
2019-12-28 17:44:24 +01:00
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// V3 Internal state
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class V3OptionsImp final {
|
2013-08-09 01:39:39 +02:00
|
|
|
public:
|
2006-08-26 13:35:28 +02:00
|
|
|
// TYPES
|
2021-03-13 00:10:45 +01:00
|
|
|
using DirMap = std::map<const string, std::set<std::string>>; // Directory listing
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// STATE
|
2020-04-15 01:55:00 +02:00
|
|
|
std::list<string> m_allArgs; // List of every argument encountered
|
|
|
|
|
std::list<string> m_incDirUsers; // Include directories (ordered)
|
|
|
|
|
std::set<string> m_incDirUserSet; // Include directories (for removing duplicates)
|
|
|
|
|
std::list<string> m_incDirFallbacks; // Include directories (ordered)
|
|
|
|
|
std::set<string> m_incDirFallbackSet; // Include directories (for removing duplicates)
|
2020-10-30 23:00:40 +01:00
|
|
|
std::map<const string, V3LangCode> m_langExts; // Language extension map
|
2020-04-15 01:55:00 +02:00
|
|
|
std::list<string> m_libExtVs; // Library extensions (ordered)
|
|
|
|
|
std::set<string> m_libExtVSet; // Library extensions (for removing duplicates)
|
|
|
|
|
DirMap m_dirMap; // Directory listing
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// ACCESSOR METHODS
|
2011-10-29 00:57:40 +02:00
|
|
|
void addIncDirUser(const string& incdir) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_incDirUserSet.find(incdir) == m_incDirUserSet.end()) {
|
2020-04-06 00:30:46 +02:00
|
|
|
// cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
|
2019-05-19 22:13:13 +02:00
|
|
|
m_incDirUserSet.insert(incdir);
|
|
|
|
|
m_incDirUsers.push_back(incdir);
|
|
|
|
|
m_incDirFallbacks.remove(incdir); // User has priority over Fallback
|
|
|
|
|
m_incDirFallbackSet.erase(incdir); // User has priority over Fallback
|
|
|
|
|
}
|
2011-10-29 00:57:40 +02:00
|
|
|
}
|
|
|
|
|
void addIncDirFallback(const string& incdir) {
|
2020-04-15 01:55:00 +02:00
|
|
|
if (m_incDirUserSet.find(incdir)
|
|
|
|
|
== m_incDirUserSet.end()) { // User has priority over Fallback
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_incDirFallbackSet.find(incdir) == m_incDirFallbackSet.end()) {
|
2020-04-06 00:30:46 +02:00
|
|
|
// cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
|
2019-05-19 22:13:13 +02:00
|
|
|
m_incDirFallbackSet.insert(incdir);
|
|
|
|
|
m_incDirFallbacks.push_back(incdir);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2013-02-03 19:27:37 +01:00
|
|
|
void addLangExt(const string& langext, const V3LangCode& lc) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// New language extension replaces any pre-existing one.
|
|
|
|
|
(void)m_langExts.erase(langext);
|
|
|
|
|
m_langExts[langext] = lc;
|
2012-11-14 02:12:23 +01:00
|
|
|
}
|
|
|
|
|
|
2012-02-12 02:40:58 +01:00
|
|
|
void addLibExtV(const string& libext) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (m_libExtVSet.find(libext) == m_libExtVSet.end()) {
|
2020-04-06 00:30:46 +02:00
|
|
|
// cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
|
2019-05-19 22:13:13 +02:00
|
|
|
m_libExtVSet.insert(libext);
|
|
|
|
|
m_libExtVs.push_back(libext);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
V3OptionsImp() = default;
|
|
|
|
|
~V3OptionsImp() = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
2020-03-15 18:39:36 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// V3LangCode class functions
|
|
|
|
|
|
|
|
|
|
V3LangCode::V3LangCode(const char* textp) {
|
|
|
|
|
// Return code for given string, or ERROR, which is a bad code
|
|
|
|
|
for (int codei = V3LangCode::L_ERROR; codei < V3LangCode::_ENUM_END; ++codei) {
|
2022-09-16 01:58:01 +02:00
|
|
|
const V3LangCode code{codei};
|
2020-03-15 18:39:36 +01:00
|
|
|
if (0 == VL_STRCASECMP(textp, code.ascii())) {
|
|
|
|
|
m_e = code;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_e = V3LangCode::L_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// VTimescale class functions
|
|
|
|
|
|
|
|
|
|
VTimescale::VTimescale(const string& value, bool& badr)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_e{VTimescale::NONE} {
|
2020-04-16 01:39:03 +02:00
|
|
|
badr = true;
|
2021-06-21 00:32:57 +02:00
|
|
|
const string spaceless = VString::removeWhitespace(value);
|
2020-05-11 14:15:52 +02:00
|
|
|
for (int i = TS_100S; i < _ENUM_END; ++i) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const VTimescale ts(i);
|
2020-04-16 01:39:03 +02:00
|
|
|
if (spaceless == ts.ascii()) {
|
|
|
|
|
badr = false;
|
|
|
|
|
m_e = ts.m_e;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// V3HierarchicalBlockOption class functions
|
|
|
|
|
|
|
|
|
|
// Parse "--hierarchical-block orig_name,mangled_name,param0_name,param0_value,... " option.
|
|
|
|
|
// The format of value is as same as -G option. (can be string literal surrounded by ")
|
|
|
|
|
V3HierarchicalBlockOption::V3HierarchicalBlockOption(const string& opts) {
|
|
|
|
|
V3StringList vals;
|
|
|
|
|
bool inStr = false;
|
|
|
|
|
string cur;
|
|
|
|
|
static const string hierBlock("--hierarchical-block");
|
|
|
|
|
FileLine cmdfl(FileLine::commandLineFilename());
|
|
|
|
|
// Split by ','. If ',' appears between "", that is not a separator.
|
|
|
|
|
for (string::const_iterator it = opts.begin(); it != opts.end();) {
|
|
|
|
|
if (inStr) {
|
|
|
|
|
if (*it == '\\') {
|
|
|
|
|
++it;
|
|
|
|
|
if (it == opts.end()) {
|
|
|
|
|
cmdfl.v3error(hierBlock + " must not end with \\");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*it != '"' && *it != '\\') {
|
|
|
|
|
cmdfl.v3error(hierBlock + " does not allow '" + *it + "' after \\");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
cur.push_back(*it);
|
|
|
|
|
++it;
|
|
|
|
|
} else if (*it == '"') { // end of string
|
|
|
|
|
cur.push_back(*it);
|
|
|
|
|
vals.push_back(cur);
|
|
|
|
|
cur.clear();
|
|
|
|
|
++it;
|
|
|
|
|
if (it != opts.end()) {
|
|
|
|
|
if (*it != ',') {
|
|
|
|
|
cmdfl.v3error(hierBlock + " expects ',', but '" + *it + "' is passed");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
++it;
|
|
|
|
|
if (it == opts.end()) {
|
|
|
|
|
cmdfl.v3error(hierBlock + " must not end with ','");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
inStr = *it == '"';
|
|
|
|
|
cur.push_back(*it);
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cur.push_back(*it);
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (*it == '"') {
|
|
|
|
|
cmdfl.v3error(hierBlock + " does not allow '\"' in the middle of literal");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*it == ',') { // end of this parameter
|
|
|
|
|
vals.push_back(cur);
|
|
|
|
|
cur.clear();
|
|
|
|
|
++it;
|
|
|
|
|
if (it == opts.end()) {
|
|
|
|
|
cmdfl.v3error(hierBlock + " must not end with ','");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
inStr = *it == '"';
|
|
|
|
|
}
|
|
|
|
|
cur.push_back(*it);
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!cur.empty()) vals.push_back(cur);
|
|
|
|
|
if (vals.size() >= 2) {
|
|
|
|
|
if (vals.size() % 2) {
|
|
|
|
|
cmdfl.v3error(hierBlock + " requires the number of entries to be even");
|
|
|
|
|
}
|
|
|
|
|
m_origName = vals[0];
|
|
|
|
|
m_mangledName = vals[1];
|
|
|
|
|
} else {
|
|
|
|
|
cmdfl.v3error(hierBlock + " requires at least two comma-separated values");
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 2; i + 1 < vals.size(); i += 2) {
|
|
|
|
|
const bool inserted = m_parameters.insert(std::make_pair(vals[i], vals[i + 1])).second;
|
|
|
|
|
if (!inserted) {
|
|
|
|
|
cmdfl.v3error("Module name '" + vals[i] + "' is duplicated in " + hierBlock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// V3Options class functions
|
|
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
void VTimescale::parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr,
|
|
|
|
|
VTimescale& precr, bool allowEmpty) {
|
|
|
|
|
// Parse `timescale of <number><units> / <number><units>
|
|
|
|
|
unitr = VTimescale::NONE;
|
|
|
|
|
precr = VTimescale::NONE;
|
|
|
|
|
|
|
|
|
|
const char* cp = textp;
|
|
|
|
|
for (; isspace(*cp); ++cp) {}
|
2021-11-13 19:50:44 +01:00
|
|
|
const char* const unitp = cp;
|
2020-04-16 01:39:03 +02:00
|
|
|
for (; *cp && *cp != '/'; ++cp) {}
|
2021-11-26 23:55:36 +01:00
|
|
|
const string unitStr(unitp, cp - unitp);
|
2020-04-16 01:39:03 +02:00
|
|
|
for (; isspace(*cp); ++cp) {}
|
|
|
|
|
string precStr;
|
|
|
|
|
if (*cp == '/') {
|
|
|
|
|
++cp;
|
|
|
|
|
for (; isspace(*cp); ++cp) {}
|
2021-11-13 19:50:44 +01:00
|
|
|
const char* const precp = cp;
|
2020-04-16 01:39:03 +02:00
|
|
|
for (; *cp && *cp != '/'; ++cp) {}
|
|
|
|
|
precStr = string(precp, cp - precp);
|
|
|
|
|
}
|
|
|
|
|
for (; isspace(*cp); ++cp) {}
|
|
|
|
|
if (*cp) {
|
|
|
|
|
fl->v3error("`timescale syntax error: '" << textp << "'");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool unitbad;
|
2021-11-26 23:55:36 +01:00
|
|
|
const VTimescale unit(unitStr, unitbad /*ref*/);
|
2020-04-16 01:39:03 +02:00
|
|
|
if (unitbad && !(unitStr.empty() && allowEmpty)) {
|
|
|
|
|
fl->v3error("`timescale timeunit syntax error: '" << unitStr << "'");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
unitr = unit;
|
|
|
|
|
|
|
|
|
|
if (!precStr.empty()) {
|
|
|
|
|
VTimescale prec(VTimescale::NONE);
|
|
|
|
|
bool precbad;
|
2022-09-16 01:58:01 +02:00
|
|
|
prec = VTimescale{precStr, precbad /*ref*/};
|
2020-04-16 01:39:03 +02:00
|
|
|
if (precbad) {
|
|
|
|
|
fl->v3error("`timescale timeprecision syntax error: '" << precStr << "'");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!unit.isNone() && !prec.isNone() && unit < prec) {
|
|
|
|
|
fl->v3error("`timescale timeunit '"
|
|
|
|
|
<< unitStr << "' must be greater than or equal to timeprecision '"
|
|
|
|
|
<< precStr << "'");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
precr = prec;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-15 18:39:36 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// V3Options class functions
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addIncDirUser(const string& incdir) { m_impp->addIncDirUser(incdir); }
|
|
|
|
|
void V3Options::addIncDirFallback(const string& incdir) { m_impp->addIncDirFallback(incdir); }
|
2013-02-03 19:27:37 +01:00
|
|
|
void V3Options::addLangExt(const string& langext, const V3LangCode& lc) {
|
2012-11-14 02:12:23 +01:00
|
|
|
m_impp->addLangExt(langext, lc);
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addLibExtV(const string& libext) { m_impp->addLibExtV(libext); }
|
2014-11-14 01:05:07 +01:00
|
|
|
void V3Options::addDefine(const string& defline, bool allowPlus) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// Split +define+foo=value into the appropriate parts and parse
|
2014-11-14 01:05:07 +01:00
|
|
|
// Optional + says to allow multiple defines on the line
|
|
|
|
|
// + is not quotable, as other simulators do not allow that
|
|
|
|
|
string left = defline;
|
|
|
|
|
while (left != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
string def = left;
|
|
|
|
|
string::size_type pos;
|
2018-10-14 04:28:59 +02:00
|
|
|
if (allowPlus && ((pos = left.find('+')) != string::npos)) {
|
2020-04-15 01:55:00 +02:00
|
|
|
left = left.substr(pos + 1);
|
2019-05-19 22:13:13 +02:00
|
|
|
def.erase(pos);
|
|
|
|
|
} else {
|
|
|
|
|
left = "";
|
|
|
|
|
}
|
|
|
|
|
string value;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = def.find('=')) != string::npos) {
|
2020-04-15 01:55:00 +02:00
|
|
|
value = def.substr(pos + 1);
|
2019-05-19 22:13:13 +02:00
|
|
|
def.erase(pos);
|
|
|
|
|
}
|
|
|
|
|
V3PreShell::defineCmdLine(def, value);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-25 00:14:15 +01:00
|
|
|
void V3Options::addParameter(const string& paramline, bool allowPlus) {
|
|
|
|
|
// Split +define+foo=value into the appropriate parts and parse
|
|
|
|
|
// Optional + says to allow multiple defines on the line
|
|
|
|
|
// + is not quotable, as other simulators do not allow that
|
|
|
|
|
string left = paramline;
|
|
|
|
|
while (left != "") {
|
|
|
|
|
string param = left;
|
|
|
|
|
string::size_type pos;
|
2018-10-14 04:28:59 +02:00
|
|
|
if (allowPlus && ((pos = left.find('+')) != string::npos)) {
|
2020-04-15 01:55:00 +02:00
|
|
|
left = left.substr(pos + 1);
|
2016-03-25 00:14:15 +01:00
|
|
|
param.erase(pos);
|
|
|
|
|
} else {
|
|
|
|
|
left = "";
|
|
|
|
|
}
|
|
|
|
|
string value;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = param.find('=')) != string::npos) {
|
2020-04-15 01:55:00 +02:00
|
|
|
value = param.substr(pos + 1);
|
2016-03-25 00:14:15 +01:00
|
|
|
param.erase(pos);
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
UINFO(4, "Add parameter" << param << "=" << value << endl);
|
2016-03-25 00:14:15 +01:00
|
|
|
(void)m_parameters.erase(param);
|
|
|
|
|
m_parameters[param] = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-08 01:31:21 +01:00
|
|
|
bool V3Options::hasParameter(const string& name) {
|
2016-03-25 00:14:15 +01:00
|
|
|
return m_parameters.find(name) != m_parameters.end();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-08 01:31:21 +01:00
|
|
|
string V3Options::parameter(const string& name) {
|
2022-07-30 17:52:35 +02:00
|
|
|
string value = m_parameters.find(name)->second;
|
2016-03-25 00:14:15 +01:00
|
|
|
m_parameters.erase(m_parameters.find(name));
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3Options::checkParameters() {
|
|
|
|
|
if (!m_parameters.empty()) {
|
2018-02-02 03:24:41 +01:00
|
|
|
std::stringstream msg;
|
2016-03-25 00:14:15 +01:00
|
|
|
msg << "Parameters from the command line were not found in the design:";
|
2020-10-30 23:00:40 +01:00
|
|
|
for (const auto& i : m_parameters) msg << " " << i.first;
|
2019-06-30 23:38:41 +02:00
|
|
|
v3error(msg.str());
|
2016-03-25 00:14:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addCppFile(const string& filename) { m_cppFiles.insert(filename); }
|
|
|
|
|
void V3Options::addCFlags(const string& filename) { m_cFlags.push_back(filename); }
|
|
|
|
|
void V3Options::addLdLibs(const string& filename) { m_ldLibs.push_back(filename); }
|
2020-04-15 23:44:21 +02:00
|
|
|
void V3Options::addMakeFlags(const string& filename) { m_makeFlags.push_back(filename); }
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addFuture(const string& flag) { m_futures.insert(flag); }
|
2022-08-20 20:01:13 +02:00
|
|
|
void V3Options::addFuture0(const string& flag) { m_future0s.insert(flag); }
|
|
|
|
|
void V3Options::addFuture1(const string& flag) { m_future1s.insert(flag); }
|
2008-07-22 20:27:34 +02:00
|
|
|
bool V3Options::isFuture(const string& flag) const {
|
|
|
|
|
return m_futures.find(flag) != m_futures.end();
|
|
|
|
|
}
|
2022-08-20 20:01:13 +02:00
|
|
|
bool V3Options::isFuture0(const string& flag) const {
|
|
|
|
|
return m_future0s.find(flag) != m_future0s.end();
|
|
|
|
|
}
|
|
|
|
|
bool V3Options::isFuture1(const string& flag) const {
|
|
|
|
|
return m_future1s.find(flag) != m_future1s.end();
|
|
|
|
|
}
|
2010-12-30 01:34:33 +01:00
|
|
|
bool V3Options::isLibraryFile(const string& filename) const {
|
|
|
|
|
return m_libraryFiles.find(filename) != m_libraryFiles.end();
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addLibraryFile(const string& filename) { m_libraryFiles.insert(filename); }
|
2015-03-13 00:20:46 +01:00
|
|
|
bool V3Options::isClocker(const string& signame) const {
|
|
|
|
|
return m_clockers.find(signame) != m_clockers.end();
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addClocker(const string& signame) { m_clockers.insert(signame); }
|
2015-03-13 00:20:46 +01:00
|
|
|
bool V3Options::isNoClocker(const string& signame) const {
|
|
|
|
|
return m_noClockers.find(signame) != m_noClockers.end();
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addNoClocker(const string& signame) { m_noClockers.insert(signame); }
|
2008-03-19 15:22:05 +01:00
|
|
|
void V3Options::addVFile(const string& filename) {
|
2008-04-09 16:17:03 +02:00
|
|
|
// We use a list for v files, because it's legal to have includes
|
|
|
|
|
// in a specific order and multiple of them.
|
|
|
|
|
m_vFiles.push_back(filename);
|
2008-03-19 15:22:05 +01:00
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(filename); }
|
2017-02-09 13:43:43 +01:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-07-03 20:16:43 +02:00
|
|
|
string V3Options::allArgsString() const {
|
2006-08-26 13:35:28 +02:00
|
|
|
string out;
|
2020-08-16 18:54:32 +02:00
|
|
|
for (const string& i : m_impp->m_allArgs) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (out != "") out += " ";
|
2020-08-16 18:54:32 +02:00
|
|
|
out += i;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
// Delete some options for Verilation of the hierarchical blocks.
|
|
|
|
|
string V3Options::allArgsStringForHierBlock(bool forTop) const {
|
|
|
|
|
std::set<string> vFiles;
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& vFile : m_vFiles) vFiles.insert(vFile);
|
2020-08-15 15:43:53 +02:00
|
|
|
string out;
|
|
|
|
|
for (std::list<string>::const_iterator it = m_impp->m_allArgs.begin();
|
|
|
|
|
it != m_impp->m_allArgs.end(); ++it) {
|
|
|
|
|
int skip = 0;
|
|
|
|
|
if (it->length() >= 2 && (*it)[0] == '-' && (*it)[1] == '-') {
|
|
|
|
|
skip = 2;
|
|
|
|
|
} else if (it->length() >= 1 && (*it)[0] == '-') {
|
|
|
|
|
skip = 1;
|
|
|
|
|
}
|
|
|
|
|
if (skip > 0) { // *it is an option
|
|
|
|
|
const string opt = it->substr(skip); // Remove '-' in the beginning
|
|
|
|
|
const int numStrip = stripOptionsForChildRun(opt, forTop);
|
|
|
|
|
if (numStrip) {
|
|
|
|
|
UASSERT(0 <= numStrip && numStrip <= 2, "should be one of 0, 1, 2");
|
|
|
|
|
if (numStrip == 2) ++it;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else { // Not an option
|
|
|
|
|
if (vFiles.find(*it) != vFiles.end() // Remove HDL
|
|
|
|
|
|| m_cppFiles.find(*it) != m_cppFiles.end()) { // Remove C++
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (out != "") out += " ";
|
|
|
|
|
// Don't use opt here because '-' is removed in it
|
|
|
|
|
// Use double quote because *it may contain whitespaces
|
|
|
|
|
out += '"' + VString::quoteAny(*it, '"', '\\') + '"';
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 02:18:40 +02:00
|
|
|
void V3Options::ccSet() { // --cc
|
|
|
|
|
m_outFormatOk = true;
|
|
|
|
|
m_systemC = false;
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// File searching
|
|
|
|
|
|
|
|
|
|
bool V3Options::fileStatNormal(const string& filename) {
|
2018-10-15 00:39:33 +02:00
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
|
|
|
|
struct stat sstat; // Stat information
|
2021-06-21 00:32:57 +02:00
|
|
|
const int err = stat(filename.c_str(), &sstat);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (err != 0) return false;
|
2014-11-24 03:06:10 +01:00
|
|
|
if (S_ISDIR(sstat.st_mode)) return false;
|
2006-08-26 13:35:28 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-05 03:21:55 +01:00
|
|
|
void V3Options::fileNfsFlush(const string& filename) {
|
|
|
|
|
// NFS caches stat() calls so to get up-to-date information must
|
|
|
|
|
// do a open or opendir on the filename.
|
|
|
|
|
// Faster to just try both rather than check if a file is a dir.
|
2021-11-13 19:50:44 +01:00
|
|
|
if (DIR* const dirp = opendir(filename.c_str())) { // LCOV_EXCL_BR_LINE
|
2020-05-17 00:02:54 +02:00
|
|
|
closedir(dirp); // LCOV_EXCL_LINE
|
2020-06-05 03:40:40 +02:00
|
|
|
} else if (int fd = ::open(filename.c_str(), O_RDONLY)) { // LCOV_EXCL_BR_LINE
|
2020-04-15 01:55:00 +02:00
|
|
|
if (fd > 0) ::close(fd);
|
2013-02-05 03:21:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-25 15:52:45 +02:00
|
|
|
string V3Options::fileExists(const string& filename) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// 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
|
|
|
|
|
|
2021-06-21 00:32:57 +02:00
|
|
|
const string dir = V3Os::filenameDir(filename);
|
|
|
|
|
const string basename = V3Os::filenameNonDir(filename);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2020-08-16 17:43:49 +02:00
|
|
|
auto diriter = m_impp->m_dirMap.find(dir);
|
2006-08-26 13:35:28 +02:00
|
|
|
if (diriter == m_impp->m_dirMap.end()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Read the listing
|
2020-12-19 00:24:47 +01:00
|
|
|
m_impp->m_dirMap.emplace(dir, std::set<string>());
|
2019-05-19 22:13:13 +02:00
|
|
|
diriter = m_impp->m_dirMap.find(dir);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2018-02-02 03:24:41 +01:00
|
|
|
std::set<string>* setp = &(diriter->second);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-11-13 19:50:44 +01:00
|
|
|
if (DIR* const dirp = opendir(dir.c_str())) {
|
2020-04-15 01:55:00 +02:00
|
|
|
while (struct dirent* direntp = readdir(dirp)) setp->insert(direntp->d_name);
|
2019-05-19 22:13:13 +02:00
|
|
|
closedir(dirp);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
// Find it
|
2021-11-26 23:55:36 +01:00
|
|
|
const std::set<string>* filesetp = &(diriter->second);
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto fileiter = filesetp->find(basename);
|
2006-08-26 13:35:28 +02:00
|
|
|
if (fileiter == filesetp->end()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return ""; // Not found
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
// Check if it is a directory, ignore if so
|
2022-07-30 17:52:35 +02:00
|
|
|
string filenameOut = V3Os::filenameFromDirBase(dir, basename);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!fileStatNormal(filenameOut)) return ""; // Directory
|
2006-08-26 13:35:28 +02:00
|
|
|
return filenameOut;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-29 00:57:40 +02:00
|
|
|
string V3Options::filePathCheckOneDir(const string& modname, const string& dirname) {
|
2020-08-16 17:43:49 +02:00
|
|
|
for (const string& i : m_impp->m_libExtVs) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string fn = V3Os::filenameFromDirBase(dirname, modname + i);
|
2019-05-19 22:13:13 +02:00
|
|
|
string exists = fileExists(fn);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (exists != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Strip ./, it just looks ugly
|
2020-04-15 01:55:00 +02:00
|
|
|
if (exists.substr(0, 2) == "./") exists.erase(0, 2);
|
2019-05-19 22:13:13 +02:00
|
|
|
return exists;
|
|
|
|
|
}
|
2011-10-29 00:57:40 +02:00
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
// Checks if a option needs to be stripped for child run of hierarchical Verilation.
|
|
|
|
|
// 0: Keep the option including its argument
|
|
|
|
|
// 1: Delete the option which has no argument
|
|
|
|
|
// 2: Delete the option and its argument
|
2020-11-11 03:40:14 +01:00
|
|
|
int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) {
|
2021-11-14 15:39:31 +01:00
|
|
|
if (opt == "Mdir" || opt == "clk" || opt == "lib-create" || opt == "f" || opt == "j"
|
|
|
|
|
|| opt == "l2-name" || opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib"
|
|
|
|
|
|| opt == "protect-key" || opt == "threads" || opt == "top-module" || opt == "v") {
|
2020-08-15 15:43:53 +02:00
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
if (opt == "build" || (!forTop && (opt == "cc" || opt == "exe" || opt == "sc"))
|
|
|
|
|
|| opt == "hierarchical" || (opt.length() > 2 && opt.substr(0, 2) == "G=")) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-25 15:52:45 +02:00
|
|
|
string V3Options::filePath(FileLine* fl, const string& modname, const string& lastpath,
|
|
|
|
|
const string& errmsg) { // Error prefix or "" to suppress error
|
2006-08-26 13:35:28 +02:00
|
|
|
// Find a filename to read the specified module name,
|
|
|
|
|
// using the incdir and libext's.
|
|
|
|
|
// Return "" if not found.
|
2020-08-16 17:43:49 +02:00
|
|
|
for (const string& dir : m_impp->m_incDirUsers) {
|
2022-07-30 17:52:35 +02:00
|
|
|
string exists = filePathCheckOneDir(modname, dir);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (exists != "") return exists;
|
2011-10-29 00:57:40 +02:00
|
|
|
}
|
2020-08-16 17:43:49 +02:00
|
|
|
for (const string& dir : m_impp->m_incDirFallbacks) {
|
2022-07-30 17:52:35 +02:00
|
|
|
string exists = filePathCheckOneDir(modname, dir);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (exists != "") return exists;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-10 00:33:18 +01:00
|
|
|
if (m_relativeIncludes) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string exists = filePathCheckOneDir(modname, lastpath);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (exists != "") return V3Os::filenameRealPath(exists);
|
2017-02-10 00:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Warn and return not found
|
2011-10-28 02:56:38 +02:00
|
|
|
if (errmsg != "") {
|
2020-04-15 01:55:00 +02:00
|
|
|
fl->v3error(errmsg + modname);
|
2019-05-19 22:13:13 +02:00
|
|
|
filePathLookedMsg(fl, modname);
|
2011-10-28 02:56:38 +02:00
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
|
2006-08-26 13:35:28 +02:00
|
|
|
static bool shown_notfound_msg = false;
|
2020-01-14 13:33:12 +01:00
|
|
|
if (modname.find("__Vhsh") != string::npos) {
|
|
|
|
|
std::cerr << V3Error::warnMore() << "... Unsupported: Name is longer than 127 characters;"
|
|
|
|
|
<< " automatic file lookup not supported.\n";
|
|
|
|
|
std::cerr << V3Error::warnMore() << "... Suggest putting filename with this module/package"
|
|
|
|
|
<< " onto command line instead.\n";
|
|
|
|
|
} else if (!shown_notfound_msg) {
|
2019-05-19 22:13:13 +02:00
|
|
|
shown_notfound_msg = true;
|
|
|
|
|
if (m_impp->m_incDirUsers.empty()) {
|
2020-11-19 03:03:23 +01:00
|
|
|
fl->v3error("This may be because there's no search path specified with -I<dir>.");
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
std::cerr << V3Error::warnMore() << "... Looked in:" << endl;
|
2020-08-16 17:43:49 +02:00
|
|
|
for (const string& dir : m_impp->m_incDirUsers) {
|
|
|
|
|
for (const string& ext : m_impp->m_libExtVs) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
|
2020-04-15 01:55:00 +02:00
|
|
|
std::cerr << V3Error::warnMore() << " " << fn << endl;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-08-16 17:43:49 +02:00
|
|
|
for (const string& dir : m_impp->m_incDirFallbacks) {
|
|
|
|
|
for (const string& ext : m_impp->m_libExtVs) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string fn = V3Os::filenameFromDirBase(dir, modname + ext);
|
2020-04-15 01:55:00 +02:00
|
|
|
std::cerr << V3Error::warnMore() << " " << fn << endl;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-14 02:12:23 +01:00
|
|
|
//! Determine what language is associated with a filename
|
|
|
|
|
|
|
|
|
|
//! If we recognize the extension, use its language, otherwise, use the
|
|
|
|
|
//! default language.
|
2020-04-15 01:55:00 +02:00
|
|
|
V3LangCode V3Options::fileLanguage(const string& filename) {
|
2015-02-27 02:40:45 +01:00
|
|
|
string ext = V3Os::filenameNonDir(filename);
|
2012-11-14 02:12:23 +01:00
|
|
|
string::size_type pos;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = ext.rfind('.')) != string::npos) {
|
2019-05-19 22:13:13 +02:00
|
|
|
ext.erase(0, pos + 1);
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it = m_impp->m_langExts.find(ext);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (it != m_impp->m_langExts.end()) return it->second;
|
2012-11-14 02:12:23 +01:00
|
|
|
}
|
|
|
|
|
return m_defaultLanguage;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-18 16:21:13 +01:00
|
|
|
//######################################################################
|
|
|
|
|
// Environment
|
|
|
|
|
|
2017-09-24 00:03:39 +02:00
|
|
|
string V3Options::getenvBuiltins(const string& var) {
|
2020-04-15 23:44:21 +02:00
|
|
|
if (var == "MAKE") {
|
|
|
|
|
return getenvMAKE();
|
|
|
|
|
} else if (var == "PERL") {
|
2020-04-15 01:55:00 +02:00
|
|
|
return getenvPERL();
|
|
|
|
|
} else if (var == "SYSTEMC") {
|
|
|
|
|
return getenvSYSTEMC();
|
|
|
|
|
} else if (var == "SYSTEMC_ARCH") {
|
|
|
|
|
return getenvSYSTEMC_ARCH();
|
|
|
|
|
} else if (var == "SYSTEMC_INCLUDE") {
|
|
|
|
|
return getenvSYSTEMC_INCLUDE();
|
|
|
|
|
} else if (var == "SYSTEMC_LIBDIR") {
|
|
|
|
|
return getenvSYSTEMC_LIBDIR();
|
|
|
|
|
} else if (var == "VERILATOR_ROOT") {
|
|
|
|
|
return getenvVERILATOR_ROOT();
|
|
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return V3Os::getenvStr(var, "");
|
2017-09-24 00:03:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-03 01:26:42 +01:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
|
string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "gmake"); }
|
|
|
|
|
#else
|
2020-04-15 23:44:21 +02:00
|
|
|
string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "make"); }
|
2020-12-03 01:26:42 +01:00
|
|
|
#endif
|
2020-04-15 23:44:21 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
string V3Options::getenvPERL() { //
|
2019-05-19 22:13:13 +02:00
|
|
|
return V3Os::getenvStr("PERL", "perl");
|
2010-12-18 01:40:08 +01:00
|
|
|
}
|
|
|
|
|
|
2008-03-18 16:21:13 +01:00
|
|
|
string V3Options::getenvSYSTEMC() {
|
2019-05-19 22:13:13 +02:00
|
|
|
string var = V3Os::getenvStr("SYSTEMC", "");
|
2008-03-18 21:26:37 +01:00
|
|
|
if (var == "" && string(DEFENV_SYSTEMC) != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
var = DEFENV_SYSTEMC;
|
|
|
|
|
V3Os::setenvStr("SYSTEMC", var, "Hardcoded at build time");
|
2008-03-18 21:26:37 +01:00
|
|
|
}
|
2008-03-18 16:21:13 +01:00
|
|
|
return var;
|
|
|
|
|
}
|
2009-03-28 14:15:13 +01:00
|
|
|
|
2008-03-18 16:21:13 +01:00
|
|
|
string V3Options::getenvSYSTEMC_ARCH() {
|
2019-05-19 22:13:13 +02:00
|
|
|
string var = V3Os::getenvStr("SYSTEMC_ARCH", "");
|
2008-03-18 21:26:37 +01:00
|
|
|
if (var == "" && string(DEFENV_SYSTEMC_ARCH) != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
var = DEFENV_SYSTEMC_ARCH;
|
|
|
|
|
V3Os::setenvStr("SYSTEMC_ARCH", var, "Hardcoded at build time");
|
2008-03-18 21:26:37 +01:00
|
|
|
}
|
2008-03-18 16:21:13 +01:00
|
|
|
if (var == "") {
|
2020-04-15 01:55:00 +02:00
|
|
|
#if defined(__MINGW32__)
|
2009-11-13 17:08:30 +01:00
|
|
|
// Hardcoded with MINGW current version. Would like a better way.
|
2021-06-21 00:32:57 +02:00
|
|
|
const string sysname = "MINGW32_NT-5.0";
|
2009-11-13 17:08:30 +01:00
|
|
|
var = "mingw32";
|
2020-04-15 01:55:00 +02:00
|
|
|
#elif defined(_WIN32)
|
2021-06-21 00:32:57 +02:00
|
|
|
const string sysname = "WIN32";
|
2010-02-01 12:41:17 +01:00
|
|
|
var = "win32";
|
2009-11-13 17:08:30 +01:00
|
|
|
#else
|
2018-10-15 00:39:33 +02:00
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
2019-05-19 22:13:13 +02:00
|
|
|
struct utsname uts;
|
|
|
|
|
uname(&uts);
|
2021-06-21 00:32:57 +02:00
|
|
|
const string sysname = VString::downcase(uts.sysname); // aka 'uname -s'
|
2020-09-07 19:11:44 +02:00
|
|
|
if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*solaris*"))) {
|
2020-04-15 01:55:00 +02:00
|
|
|
var = "gccsparcOS5";
|
2020-09-07 19:11:44 +02:00
|
|
|
} else if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*cygwin*"))) {
|
2020-04-15 01:55:00 +02:00
|
|
|
var = "cygwin";
|
|
|
|
|
} else {
|
|
|
|
|
var = "linux";
|
|
|
|
|
}
|
2009-11-13 17:08:30 +01:00
|
|
|
#endif
|
2020-04-15 01:55:00 +02:00
|
|
|
V3Os::setenvStr("SYSTEMC_ARCH", var, "From sysname '" + sysname + "'");
|
2008-03-18 16:21:13 +01:00
|
|
|
}
|
|
|
|
|
return var;
|
|
|
|
|
}
|
2009-03-28 14:15:13 +01:00
|
|
|
|
2012-01-20 02:30:41 +01:00
|
|
|
string V3Options::getenvSYSTEMC_INCLUDE() {
|
2019-05-19 22:13:13 +02:00
|
|
|
string var = V3Os::getenvStr("SYSTEMC_INCLUDE", "");
|
2012-01-20 02:30:41 +01:00
|
|
|
if (var == "" && string(DEFENV_SYSTEMC_INCLUDE) != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
var = DEFENV_SYSTEMC_INCLUDE;
|
|
|
|
|
V3Os::setenvStr("SYSTEMC_INCLUDE", var, "Hardcoded at build time");
|
2012-01-20 02:30:41 +01:00
|
|
|
}
|
|
|
|
|
if (var == "") {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string sc = getenvSYSTEMC();
|
2020-04-15 01:55:00 +02:00
|
|
|
if (sc != "") var = sc + "/include";
|
2012-01-20 02:30:41 +01:00
|
|
|
}
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string V3Options::getenvSYSTEMC_LIBDIR() {
|
2019-05-19 22:13:13 +02:00
|
|
|
string var = V3Os::getenvStr("SYSTEMC_LIBDIR", "");
|
2012-01-20 02:30:41 +01:00
|
|
|
if (var == "" && string(DEFENV_SYSTEMC_LIBDIR) != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
var = DEFENV_SYSTEMC_LIBDIR;
|
|
|
|
|
V3Os::setenvStr("SYSTEMC_LIBDIR", var, "Hardcoded at build time");
|
2012-01-20 02:30:41 +01:00
|
|
|
}
|
|
|
|
|
if (var == "") {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string sc = getenvSYSTEMC();
|
|
|
|
|
const string arch = getenvSYSTEMC_ARCH();
|
2020-04-15 01:55:00 +02:00
|
|
|
if (sc != "" && arch != "") var = sc + "/lib-" + arch;
|
2012-01-20 02:30:41 +01:00
|
|
|
}
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-18 16:21:13 +01:00
|
|
|
string V3Options::getenvVERILATOR_ROOT() {
|
2019-05-19 22:13:13 +02:00
|
|
|
string var = V3Os::getenvStr("VERILATOR_ROOT", "");
|
2008-03-18 21:26:37 +01:00
|
|
|
if (var == "" && string(DEFENV_VERILATOR_ROOT) != "") {
|
2019-05-19 22:13:13 +02:00
|
|
|
var = DEFENV_VERILATOR_ROOT;
|
|
|
|
|
V3Os::setenvStr("VERILATOR_ROOT", var, "Hardcoded at build time");
|
2008-03-18 21:26:37 +01:00
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
if (var == "") v3fatal("$VERILATOR_ROOT needs to be in environment\n");
|
2008-03-18 16:21:13 +01:00
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-29 00:51:46 +02:00
|
|
|
bool V3Options::systemCSystemWide() {
|
2020-06-28 18:17:54 +02:00
|
|
|
#ifdef HAVE_SYSTEMC
|
2020-05-29 00:51:46 +02:00
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool V3Options::systemCFound() {
|
|
|
|
|
return (systemCSystemWide()
|
|
|
|
|
|| (!getenvSYSTEMC_INCLUDE().empty() && !getenvSYSTEMC_LIBDIR().empty()));
|
|
|
|
|
}
|
|
|
|
|
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
bool V3Options::coroutineSupport() {
|
|
|
|
|
#ifdef HAVE_COROUTINES
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-04 04:18:29 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// V3 Options notification methods
|
|
|
|
|
|
|
|
|
|
void V3Options::notify() {
|
|
|
|
|
// Notify that all arguments have been passed and final modification can be made.
|
2022-09-15 02:18:40 +02:00
|
|
|
FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()};
|
|
|
|
|
|
|
|
|
|
if (!outFormatOk() && v3Global.opt.main()) ccSet(); // --main implies --cc if not provided
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) {
|
2022-09-28 15:04:14 +02:00
|
|
|
v3fatal("verilator: Need --binary, --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, "
|
2020-04-15 01:55:00 +02:00
|
|
|
"--xml-only or --E option");
|
2019-10-04 04:18:29 +02:00
|
|
|
}
|
2019-10-18 01:44:10 +02:00
|
|
|
|
2022-01-16 16:30:44 +01:00
|
|
|
if (cdc()) {
|
|
|
|
|
cmdfl->v3warn(DEPRECATED, "Option --cdc is deprecated and is planned for removal");
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-30 13:54:50 +02:00
|
|
|
if (m_build && (m_gmake || m_cmake)) {
|
|
|
|
|
cmdfl->v3error("--make cannot be used together with --build. Suggest see manual");
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 01:44:10 +02:00
|
|
|
// Make sure at least one make system is enabled
|
2020-04-15 01:55:00 +02:00
|
|
|
if (!m_gmake && !m_cmake) m_gmake = true;
|
2019-10-18 01:44:10 +02:00
|
|
|
|
2020-08-15 15:43:53 +02:00
|
|
|
if (m_hierarchical && (m_hierChild || !m_hierBlocks.empty())) {
|
|
|
|
|
cmdfl->v3error(
|
|
|
|
|
"--hierarchical must not be set with --hierarchical-child or --hierarchical-block");
|
|
|
|
|
}
|
|
|
|
|
if (m_hierChild && m_hierBlocks.empty()) {
|
|
|
|
|
cmdfl->v3error("--hierarchical-block must be set when --hierarchical-child is set");
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-06 19:24:21 +02:00
|
|
|
if (protectIds()) {
|
|
|
|
|
if (allPublic()) {
|
|
|
|
|
// We always call protect() on names, we don't check if public or not
|
|
|
|
|
// Hence any external references wouldn't be able to find the refed public object.
|
2020-06-10 01:20:16 +02:00
|
|
|
cmdfl->v3warn(E_UNSUPPORTED, "Unsupported: Using --protect-ids with --public\n" //
|
|
|
|
|
+ V3Error::warnMore()
|
|
|
|
|
+ "... Suggest remove --public.");
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
if (trace()) {
|
|
|
|
|
cmdfl->v3warn(INSECURE,
|
|
|
|
|
"Using --protect-ids with --trace may expose private design details\n"
|
2020-04-15 01:55:00 +02:00
|
|
|
+ V3Error::warnMore() + "... Suggest remove --trace.");
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
if (vpi()) {
|
|
|
|
|
cmdfl->v3warn(INSECURE,
|
|
|
|
|
"Using --protect-ids with --vpi may expose private design details\n"
|
2020-04-15 01:55:00 +02:00
|
|
|
+ V3Error::warnMore() + "... Suggest remove --vpi.");
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-11-01 01:59:52 +01:00
|
|
|
|
|
|
|
|
// Default some options if not turned on or off
|
|
|
|
|
if (v3Global.opt.skipIdentical().isDefault()) {
|
2020-04-15 01:55:00 +02:00
|
|
|
v3Global.opt.m_skipIdentical.setTrueOrFalse( //
|
|
|
|
|
!v3Global.opt.cdc() //
|
|
|
|
|
&& !v3Global.opt.dpiHdrOnly() //
|
|
|
|
|
&& !v3Global.opt.lintOnly() //
|
|
|
|
|
&& !v3Global.opt.preprocOnly() //
|
2019-11-01 02:17:05 +01:00
|
|
|
&& !v3Global.opt.xmlOnly());
|
2019-11-01 01:59:52 +01:00
|
|
|
}
|
|
|
|
|
if (v3Global.opt.makeDepend().isDefault()) {
|
2020-04-15 01:55:00 +02:00
|
|
|
v3Global.opt.m_makeDepend.setTrueOrFalse( //
|
|
|
|
|
!v3Global.opt.cdc() //
|
|
|
|
|
&& !v3Global.opt.dpiHdrOnly() //
|
|
|
|
|
&& !v3Global.opt.lintOnly() //
|
|
|
|
|
&& !v3Global.opt.preprocOnly() //
|
2019-11-01 02:17:05 +01:00
|
|
|
&& !v3Global.opt.xmlOnly());
|
2019-11-01 01:59:52 +01:00
|
|
|
}
|
2020-04-22 00:49:07 +02:00
|
|
|
|
2022-05-29 20:08:39 +02:00
|
|
|
if (trace()) {
|
|
|
|
|
// With --trace-fst, --trace-threads implies --threads 1 unless explicitly specified
|
|
|
|
|
if (traceFormat().fst() && traceThreads() && !threads()) m_threads = 1;
|
|
|
|
|
|
|
|
|
|
// With --trace, --trace-threads is ignored
|
|
|
|
|
if (traceFormat().vcd()) m_traceThreads = threads() ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UASSERT(!(useTraceParallel() && useTraceOffload()),
|
|
|
|
|
"Cannot use both parallel and offloaded tracing");
|
2020-04-22 02:45:23 +02:00
|
|
|
|
2020-05-25 23:15:16 +02:00
|
|
|
// Default split limits if not specified
|
|
|
|
|
if (m_outputSplitCFuncs < 0) m_outputSplitCFuncs = m_outputSplit;
|
|
|
|
|
if (m_outputSplitCTrace < 0) m_outputSplitCTrace = m_outputSplit;
|
|
|
|
|
|
2020-04-22 02:45:23 +02:00
|
|
|
if (v3Global.opt.main() && v3Global.opt.systemC()) {
|
2020-06-10 01:20:16 +02:00
|
|
|
cmdfl->v3warn(E_UNSUPPORTED,
|
|
|
|
|
"--main not usable with SystemC. Suggest see examples for sc_main().");
|
2020-04-22 02:45:23 +02:00
|
|
|
}
|
2021-05-22 13:27:32 +02:00
|
|
|
|
|
|
|
|
if (coverage() && savable()) {
|
|
|
|
|
cmdfl->v3error("--coverage and --savable not supported together");
|
|
|
|
|
}
|
2021-07-10 13:03:51 +02:00
|
|
|
|
|
|
|
|
// Mark options as available
|
|
|
|
|
m_available = true;
|
2022-10-01 17:05:33 +02:00
|
|
|
|
|
|
|
|
// --dump-tree-dot will turn on tree dumping.
|
|
|
|
|
if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-dot")) {
|
|
|
|
|
m_dumpLevel["tree"] = m_dumpLevel["tree-dot"];
|
|
|
|
|
}
|
2022-10-18 00:18:56 +02:00
|
|
|
|
|
|
|
|
// Preprocessor defines based on options used
|
|
|
|
|
if (timing().isSetTrue()) V3PreShell::defineCmdLine("VERILATOR_TIMING", "1");
|
2019-10-04 04:18:29 +02:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// V3 Options accessors
|
|
|
|
|
|
|
|
|
|
string V3Options::version() {
|
|
|
|
|
string ver = DTVERSION;
|
2020-04-15 01:55:00 +02:00
|
|
|
ver += " rev " + cvtToStr(DTVERSION_rev);
|
2006-08-26 13:35:28 +02:00
|
|
|
return ver;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-06 19:24:21 +02:00
|
|
|
string V3Options::protectKeyDefaulted() {
|
|
|
|
|
if (m_protectKey.empty()) {
|
|
|
|
|
// Create a key with a human-readable symbol-like name.
|
|
|
|
|
// This conversion drops ~2 bits of entropy out of 256, shouldn't matter.
|
2020-04-15 01:55:00 +02:00
|
|
|
VHashSha256 digest(V3Os::trueRandom(32));
|
|
|
|
|
m_protectKey = "VL-KEY-" + digest.digestSymbol();
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
return m_protectKey;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-05 03:40:40 +02:00
|
|
|
void V3Options::throwSigsegv() { // LCOV_EXCL_START
|
2017-07-07 02:25:59 +02:00
|
|
|
#if !(defined(VL_CPPCHECK) || defined(__clang_analyzer__))
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format off
|
2021-06-13 00:03:32 +02:00
|
|
|
*static_cast<volatile char*>(nullptr) = 0; // Intentional core dump, ignore warnings here
|
2020-04-15 01:55:00 +02:00
|
|
|
// clang-format on
|
2017-07-07 02:25:59 +02:00
|
|
|
#endif
|
2020-06-05 03:40:40 +02:00
|
|
|
} // LCOV_EXCL_STOP
|
2011-08-05 03:58:45 +02:00
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
VTimescale V3Options::timeComputePrec(const VTimescale& flag) const {
|
|
|
|
|
if (!timeOverridePrec().isNone()) {
|
|
|
|
|
return timeOverridePrec();
|
|
|
|
|
} else if (flag.isNone()) {
|
|
|
|
|
return timeDefaultPrec();
|
|
|
|
|
} else {
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VTimescale V3Options::timeComputeUnit(const VTimescale& flag) const {
|
|
|
|
|
if (!timeOverrideUnit().isNone()) {
|
|
|
|
|
return timeOverrideUnit();
|
|
|
|
|
} else if (flag.isNone()) {
|
|
|
|
|
return timeDefaultUnit();
|
|
|
|
|
} else {
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// V3 Options utilities
|
|
|
|
|
|
2018-08-25 15:52:45 +02:00
|
|
|
string V3Options::argString(int argc, char** argv) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// Return list of arguments as simple string
|
|
|
|
|
string opts;
|
2020-04-15 01:55:00 +02:00
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
|
|
|
if (i != 0) opts += " ";
|
2019-05-19 22:13:13 +02:00
|
|
|
opts += string(argv[i]);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return opts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// V3 Options Parsing
|
|
|
|
|
|
2018-08-25 15:52:45 +02:00
|
|
|
void V3Options::parseOpts(FileLine* fl, int argc, char** argv) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// Parse all options
|
2019-09-09 13:50:21 +02:00
|
|
|
// Initial entry point from Verilator.cpp
|
2018-08-25 15:52:45 +02:00
|
|
|
parseOptsList(fl, ".", argc, argv);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Default certain options and error check
|
|
|
|
|
// Detailed error, since this is what we often get when run with minimal arguments
|
2014-06-09 03:36:18 +02:00
|
|
|
const V3StringList& vFilesList = vFiles();
|
|
|
|
|
if (vFilesList.empty()) {
|
2020-04-15 01:55:00 +02:00
|
|
|
v3fatal("verilator: No Input Verilog file specified on command line, "
|
|
|
|
|
"see verilator --help for more information\n");
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default prefix to the filename
|
2021-01-27 02:10:27 +01:00
|
|
|
if (prefix() == "" && topModule() != "")
|
|
|
|
|
m_prefix = string("V") + AstNode::encodeName(topModule());
|
|
|
|
|
if (prefix() == "" && vFilesList.size() >= 1)
|
|
|
|
|
m_prefix = string("V") + AstNode::encodeName(V3Os::filenameNonExt(*(vFilesList.begin())));
|
2020-04-15 01:55:00 +02:00
|
|
|
if (modPrefix() == "") m_modPrefix = prefix();
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Find files in makedir
|
2011-10-29 00:57:40 +02:00
|
|
|
addIncDirFallback(makeDir());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
2015-10-30 03:19:51 +01:00
|
|
|
bool V3Options::suffixed(const string& sw, const char* arg) {
|
2022-09-15 03:10:19 +02:00
|
|
|
if (std::strlen(arg) > sw.length()) return false;
|
|
|
|
|
return (0 == std::strcmp(sw.c_str() + sw.length() - std::strlen(arg), arg));
|
2010-01-29 01:33:02 +01:00
|
|
|
}
|
|
|
|
|
|
2010-11-03 12:02:32 +01:00
|
|
|
void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// Parse parameters
|
|
|
|
|
// Note argc and argv DO NOT INCLUDE the filename in [0]!!!
|
|
|
|
|
// May be called recursively when there are -f files.
|
2020-04-15 01:55:00 +02:00
|
|
|
for (int i = 0; i < argc; ++i) {
|
2019-05-19 22:13:13 +02:00
|
|
|
addArg(argv[i]); // -f's really should be inserted in the middle, but this is for debug
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
|
2021-05-03 23:30:18 +02:00
|
|
|
V3OptionParser parser;
|
2021-11-26 23:55:36 +01:00
|
|
|
const V3OptionParser::AppendHelper DECL_OPTION{parser};
|
2021-05-03 23:30:18 +02:00
|
|
|
V3OPTION_PARSER_DECL_TAGS;
|
|
|
|
|
|
2021-06-21 00:32:57 +02:00
|
|
|
const auto callStrSetter = [this](void (V3Options::*cbStr)(const string&)) {
|
2021-05-03 23:30:18 +02:00
|
|
|
return [this, cbStr](const string& v) { (this->*cbStr)(v); };
|
|
|
|
|
};
|
2021-03-26 14:48:24 +01:00
|
|
|
// Usage
|
|
|
|
|
// DECL_OPTION("-option", action, pointer_or_lambda);
|
|
|
|
|
// action: one of Set, OnOff, CbCall, CbOnOff, CbVal, CbPartialMatch, and CbPartialMatchVal
|
|
|
|
|
// Set : Set value to a variable, pointer_or_lambda must be a pointer to the
|
2021-05-03 23:30:18 +02:00
|
|
|
// variable.
|
2021-03-26 14:48:24 +01:00
|
|
|
// true is set to bool-ish variable when '-opt' is passed to verilator.
|
|
|
|
|
// val is set to int and string variable when '-opt val' is passed.
|
|
|
|
|
// OnOff : Set value to a bool-ish variable, pointer_or_lambda must be a pointer
|
|
|
|
|
// to bool or VOptionBool.
|
|
|
|
|
// true is set if "-opt" is passed to verilator while false is set if
|
|
|
|
|
// "-no-opt" is given.
|
|
|
|
|
// CbCall : Call lambda or function that does not take argument.
|
|
|
|
|
// CbOnOff : Call lambda or function that takes bool argument.
|
|
|
|
|
// Supports "-opt" and "-no-opt" style options.
|
|
|
|
|
// CbVal : Call lambda or function that takes int or const char*.
|
|
|
|
|
// "-opt val" is passed to verilator, val is passed to the lambda.
|
|
|
|
|
// If a function to be called is a member of V3Options that only takes
|
2021-05-03 23:30:18 +02:00
|
|
|
// const string&, callStrSetter(&V3Options::memberFunc) can be passed
|
2021-03-26 14:48:24 +01:00
|
|
|
// instead of lambda as a syntax sugar.
|
|
|
|
|
// CbPartialMatch : Call lambda or function that takes remaining string.
|
|
|
|
|
// e.g. DECL_OPTION("-opt-", CbPartialMatch, [](const char*optp) { cout <<
|
|
|
|
|
// optp << endl; }); and "-opt-ABC" is passed, "ABC" will be emit to
|
|
|
|
|
// stdout.
|
|
|
|
|
// CbPartialMatchVal: Call lambda or function that takes remaining string and value.
|
|
|
|
|
// e.g. DECL_OPTION("-opt-", CbPartialMatchVal, [](const char*optp, const
|
|
|
|
|
// char*valp) {
|
|
|
|
|
// cout << optp << ":" << valp << endl; });
|
|
|
|
|
// and "-opt-ABC VAL" is passed, "ABC:VAL" will be emit to stdout.
|
|
|
|
|
//
|
|
|
|
|
// DECL_OPTION is not C-macro to get correct line coverage even when lambda is passed.
|
|
|
|
|
// (If DECL_OPTION is a macro, then lambda would be collapsed into a single line).
|
|
|
|
|
|
|
|
|
|
// Plus options
|
|
|
|
|
DECL_OPTION("+define+", CbPartialMatch, [this](const char* optp) { addDefine(optp, true); });
|
|
|
|
|
DECL_OPTION("+incdir+", CbPartialMatch,
|
|
|
|
|
[this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); });
|
|
|
|
|
DECL_OPTION("+libext+", CbPartialMatch, [this](const char* optp) {
|
|
|
|
|
string exts = optp;
|
|
|
|
|
string::size_type pos;
|
|
|
|
|
while ((pos = exts.find('+')) != string::npos) {
|
|
|
|
|
addLibExtV(exts.substr(0, pos));
|
|
|
|
|
exts = exts.substr(pos + 1);
|
|
|
|
|
}
|
|
|
|
|
addLibExtV(exts);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("+librescan", CbCall, []() {}); // NOP
|
|
|
|
|
DECL_OPTION("+notimingchecks", CbCall, []() {}); // NOP
|
|
|
|
|
DECL_OPTION("+systemverilogext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2017); });
|
|
|
|
|
DECL_OPTION("+verilog1995ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1364_1995); });
|
|
|
|
|
DECL_OPTION("+verilog2001ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1364_2001); });
|
|
|
|
|
DECL_OPTION("+1364-1995ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1364_1995); });
|
|
|
|
|
DECL_OPTION("+1364-2001ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1364_2001); });
|
|
|
|
|
DECL_OPTION("+1364-2005ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1364_2005); });
|
|
|
|
|
DECL_OPTION("+1800-2005ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2005); });
|
|
|
|
|
DECL_OPTION("+1800-2009ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2009); });
|
|
|
|
|
DECL_OPTION("+1800-2012ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2012); });
|
|
|
|
|
DECL_OPTION("+1800-2017ext+", CbPartialMatch,
|
|
|
|
|
[this](const char* optp) { addLangExt(optp, V3LangCode::L1800_2017); });
|
|
|
|
|
|
|
|
|
|
// Minus options
|
|
|
|
|
DECL_OPTION("-assert", OnOff, &m_assert);
|
|
|
|
|
DECL_OPTION("-autoflush", OnOff, &m_autoflush);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-bbox-sys", OnOff, &m_bboxSys);
|
|
|
|
|
DECL_OPTION("-bbox-unsup", CbOnOff, [this](bool flag) {
|
|
|
|
|
m_bboxUnsup = flag;
|
|
|
|
|
FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, true);
|
|
|
|
|
});
|
2022-09-28 15:04:14 +02:00
|
|
|
DECL_OPTION("-binary", CbCall, [this]() {
|
|
|
|
|
m_build = true;
|
|
|
|
|
m_exe = true;
|
|
|
|
|
m_main = true;
|
2022-09-29 01:02:07 +02:00
|
|
|
if (m_timing.isDefault()) m_timing = VOptionBool::OPT_TRUE;
|
2022-09-28 15:04:14 +02:00
|
|
|
});
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-build", Set, &m_build);
|
2022-09-18 16:32:43 +02:00
|
|
|
DECL_OPTION("-build-dep-bin", Set, &m_buildDepBin);
|
2022-09-15 14:28:58 +02:00
|
|
|
DECL_OPTION("-build-jobs", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
int val = std::atoi(valp);
|
|
|
|
|
if (val < 0) {
|
|
|
|
|
fl->v3fatal("--build-jobs requires a non-negative integer, but '" << valp
|
|
|
|
|
<< "' was passed");
|
|
|
|
|
val = 1;
|
|
|
|
|
} else if (val == 0) {
|
|
|
|
|
val = std::thread::hardware_concurrency();
|
|
|
|
|
}
|
|
|
|
|
m_buildJobs = val;
|
|
|
|
|
});
|
2021-03-26 14:48:24 +01:00
|
|
|
|
2021-05-03 23:30:18 +02:00
|
|
|
DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags));
|
2022-09-15 02:18:40 +02:00
|
|
|
DECL_OPTION("-cc", CbCall, [this]() { ccSet(); });
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-cdc", OnOff, &m_cdc);
|
2021-05-03 23:30:18 +02:00
|
|
|
DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker));
|
|
|
|
|
DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker));
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-comp-limit-blocks", Set, &m_compLimitBlocks).undocumented();
|
|
|
|
|
DECL_OPTION("-comp-limit-members", Set,
|
|
|
|
|
&m_compLimitMembers)
|
|
|
|
|
.undocumented(); // Ideally power-of-two so structs stay aligned
|
|
|
|
|
DECL_OPTION("-comp-limit-parens", Set, &m_compLimitParens).undocumented();
|
|
|
|
|
DECL_OPTION("-comp-limit-syms", CbVal, [](int val) { VName::maxLength(val); }).undocumented();
|
|
|
|
|
DECL_OPTION("-compiler", CbVal, [this, fl](const char* valp) {
|
2022-09-15 03:10:19 +02:00
|
|
|
if (!std::strcmp(valp, "clang")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_compLimitBlocks = 80; // limit unknown
|
|
|
|
|
m_compLimitMembers = 64; // soft limit, has slowdown bug as of clang++ 3.8
|
2022-07-25 13:59:26 +02:00
|
|
|
m_compLimitParens = 240; // controlled by -fbracket-depth, which defaults to 256
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "gcc")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_compLimitBlocks = 0; // Bug free
|
|
|
|
|
m_compLimitMembers = 64; // soft limit, has slowdown bug as of g++ 7.1
|
2022-07-25 13:59:26 +02:00
|
|
|
m_compLimitParens = 240; // Unlimited, but generate same code as for clang
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "msvc")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_compLimitBlocks = 80; // 128, but allow some room
|
|
|
|
|
m_compLimitMembers = 0; // probably ok, and AFAIK doesn't support anon structs
|
|
|
|
|
m_compLimitParens = 80; // 128, but allow some room
|
|
|
|
|
} else {
|
|
|
|
|
fl->v3fatal("Unknown setting for --compiler: '"
|
|
|
|
|
<< valp << "'\n"
|
|
|
|
|
<< fl->warnMore() << "... Suggest 'clang', 'gcc', or 'msvc'");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-coverage", CbOnOff, [this](bool flag) { coverage(flag); });
|
|
|
|
|
DECL_OPTION("-converge-limit", Set, &m_convergeLimit);
|
|
|
|
|
DECL_OPTION("-coverage-line", OnOff, &m_coverageLine);
|
2021-03-30 00:54:51 +02:00
|
|
|
DECL_OPTION("-coverage-max-width", Set, &m_coverageMaxWidth);
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-coverage-toggle", OnOff, &m_coverageToggle);
|
|
|
|
|
DECL_OPTION("-coverage-underscore", OnOff, &m_coverageUnderscore);
|
|
|
|
|
DECL_OPTION("-coverage-user", OnOff, &m_coverageUser);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-D", CbPartialMatch, [this](const char* valp) { addDefine(valp, false); });
|
|
|
|
|
DECL_OPTION("-debug", CbCall, [this]() { setDebugMode(3); });
|
2021-05-03 23:30:18 +02:00
|
|
|
DECL_OPTION("-debugi", CbVal, [this](int v) { setDebugMode(v); });
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
|
2022-09-18 21:53:42 +02:00
|
|
|
m_debugLevel[optp] = std::atoi(valp);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
DECL_OPTION("-debug-abort", CbCall,
|
|
|
|
|
V3Error::vlAbort)
|
|
|
|
|
.undocumented(); // See also --debug-sigsegv
|
|
|
|
|
DECL_OPTION("-debug-check", OnOff, &m_debugCheck);
|
|
|
|
|
DECL_OPTION("-debug-collision", OnOff, &m_debugCollision).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-emitv", OnOff, &m_debugEmitV).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-exit-parse", OnOff, &m_debugExitParse).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-exit-uvm", OnOff, &m_debugExitUvm).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-fatalsrc", CbCall, []() {
|
|
|
|
|
v3fatalSrc("--debug-fatal-src");
|
|
|
|
|
}).undocumented(); // See also --debug-abort
|
|
|
|
|
DECL_OPTION("-debug-leak", OnOff, &m_debugLeak);
|
|
|
|
|
DECL_OPTION("-debug-nondeterminism", OnOff, &m_debugNondeterminism);
|
|
|
|
|
DECL_OPTION("-debug-partition", OnOff, &m_debugPartition).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-protect", OnOff, &m_debugProtect).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented();
|
|
|
|
|
DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort
|
|
|
|
|
DECL_OPTION("-decoration", OnOff, &m_decoration);
|
|
|
|
|
DECL_OPTION("-dpi-hdr-only", OnOff, &m_dpiHdrOnly);
|
2022-09-18 21:53:42 +02:00
|
|
|
DECL_OPTION("-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 3; });
|
|
|
|
|
DECL_OPTION("-no-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 0; });
|
|
|
|
|
DECL_OPTION("-dumpi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
|
|
|
|
|
m_dumpLevel[optp] = std::atoi(valp);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
DECL_OPTION("-E", Set, &m_preprocOnly);
|
|
|
|
|
DECL_OPTION("-error-limit", CbVal, static_cast<void (*)(int)>(&V3Error::errorLimit));
|
|
|
|
|
DECL_OPTION("-exe", OnOff, &m_exe);
|
2021-06-06 16:27:01 +02:00
|
|
|
DECL_OPTION("-expand-limit", CbVal,
|
2021-06-06 16:32:50 +02:00
|
|
|
[this](const char* valp) { m_expandLimit = std::atoi(valp); });
|
2021-03-26 14:48:24 +01:00
|
|
|
|
|
|
|
|
DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) {
|
|
|
|
|
parseOptsFile(fl, parseFileArg(optdir, valp), true);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-FI", CbVal,
|
|
|
|
|
[this, &optdir](const char* valp) { addForceInc(parseFileArg(optdir, valp)); });
|
|
|
|
|
DECL_OPTION("-f", CbVal, [this, fl, &optdir](const char* valp) {
|
|
|
|
|
parseOptsFile(fl, parseFileArg(optdir, valp), false);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-flatten", OnOff, &m_flatten);
|
2022-08-20 20:19:00 +02:00
|
|
|
DECL_OPTION("-future0", CbVal, [this](const char* valp) { addFuture0(valp); });
|
|
|
|
|
DECL_OPTION("-future1", CbVal, [this](const char* valp) { addFuture1(valp); });
|
2021-03-26 14:48:24 +01:00
|
|
|
|
2022-06-04 02:43:16 +02:00
|
|
|
DECL_OPTION("-facyc-simp", FOnOff, &m_fAcycSimp);
|
|
|
|
|
DECL_OPTION("-fassemble", FOnOff, &m_fAssemble);
|
|
|
|
|
DECL_OPTION("-fcase", FOnOff, &m_fCase);
|
|
|
|
|
DECL_OPTION("-fcombine", FOnOff, &m_fCombine);
|
|
|
|
|
DECL_OPTION("-fconst", FOnOff, &m_fConst);
|
2022-10-04 22:18:39 +02:00
|
|
|
DECL_OPTION("-fconst-before-dfg", FOnOff, &m_fConstBeforeDfg);
|
2022-06-04 02:43:16 +02:00
|
|
|
DECL_OPTION("-fconst-bit-op-tree", FOnOff, &m_fConstBitOpTree);
|
|
|
|
|
DECL_OPTION("-fdedup", FOnOff, &m_fDedupe);
|
Introduce DFG based combinational logic optimizer (#3527)
Added a new data-flow graph (DFG) based combinational logic optimizer.
The capabilities of this covers a combination of V3Const and V3Gate, but
is also more capable of transforming combinational logic into simplified
forms and more.
This entail adding a new internal representation, `DfgGraph`, and
appropriate `astToDfg` and `dfgToAst` conversion functions. The graph
represents some of the combinational equations (~continuous assignments)
in a module, and for the duration of the DFG passes, it takes over the
role of AstModule. A bulk of the Dfg vertices represent expressions.
These vertex classes, and the corresponding conversions to/from AST are
mostly auto-generated by astgen, together with a DfgVVisitor that can be
used for dynamic dispatch based on vertex (operation) types.
The resulting combinational logic graph (a `DfgGraph`) is then optimized
in various ways. Currently we perform common sub-expression elimination,
variable inlining, and some specific peephole optimizations, but there
is scope for more optimizations in the future using the same
representation. The optimizer is run directly before and after inlining.
The pre inline pass can operate on smaller graphs and hence converges
faster, but still has a chance of substantially reducing the size of the
logic on some designs, making inlining both faster and less memory
intensive. The post inline pass can then optimize across the inlined
module boundaries. No optimization is performed across a module
boundary.
For debugging purposes, each peephole optimization can be disabled
individually via the -fno-dfg-peepnole-<OPT> option, where <OPT> is one
of the optimizations listed in V3DfgPeephole.h, for example
-fno-dfg-peephole-remove-not-not.
The peephole patterns currently implemented were mostly picked based on
the design that inspired this work, and on that design the optimizations
yields ~30% single threaded speedup, and ~50% speedup on 4 threads. As
you can imagine not having to haul around redundant combinational
networks in the rest of the compilation pipeline also helps with memory
consumption, and up to 30% peak memory usage of Verilator was observed
on the same design.
Gains on other arbitrary designs are smaller (and can be improved by
analyzing those designs). For example OpenTitan gains between 1-15%
speedup depending on build type.
2022-09-23 17:46:22 +02:00
|
|
|
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) {
|
|
|
|
|
m_fDfgPreInline = flag;
|
|
|
|
|
m_fDfgPostInline = flag;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-fdfg-peephole", FOnOff, &m_fDfgPeephole);
|
|
|
|
|
DECL_OPTION("-fdfg-peephole-", CbPartialMatch, [this](const char* optp) { //
|
|
|
|
|
m_fDfgPeepholeDisabled.erase(optp);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-fno-dfg-peephole-", CbPartialMatch, [this](const char* optp) { //
|
|
|
|
|
m_fDfgPeepholeDisabled.emplace(optp);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-fdfg-pre-inline", FOnOff, &m_fDfgPreInline);
|
|
|
|
|
DECL_OPTION("-fdfg-post-inline", FOnOff, &m_fDfgPostInline);
|
2022-06-04 02:43:16 +02:00
|
|
|
DECL_OPTION("-fexpand", FOnOff, &m_fExpand);
|
|
|
|
|
DECL_OPTION("-fgate", FOnOff, &m_fGate);
|
|
|
|
|
DECL_OPTION("-finline", FOnOff, &m_fInline);
|
|
|
|
|
DECL_OPTION("-flife", FOnOff, &m_fLife);
|
|
|
|
|
DECL_OPTION("-flife-post", FOnOff, &m_fLifePost);
|
|
|
|
|
DECL_OPTION("-flocalize", FOnOff, &m_fLocalize);
|
|
|
|
|
DECL_OPTION("-fmerge-cond", FOnOff, &m_fMergeCond);
|
2022-06-13 15:16:11 +02:00
|
|
|
DECL_OPTION("-fmerge-cond-motion", FOnOff, &m_fMergeCondMotion);
|
2022-06-04 01:41:59 +02:00
|
|
|
DECL_OPTION("-fmerge-const-pool", FOnOff, &m_fMergeConstPool);
|
2022-06-04 02:43:16 +02:00
|
|
|
DECL_OPTION("-freloop", FOnOff, &m_fReloop);
|
|
|
|
|
DECL_OPTION("-freorder", FOnOff, &m_fReorder);
|
|
|
|
|
DECL_OPTION("-fsplit", FOnOff, &m_fSplit);
|
|
|
|
|
DECL_OPTION("-fsubst", FOnOff, &m_fSubst);
|
|
|
|
|
DECL_OPTION("-fsubst-const", FOnOff, &m_fSubstConst);
|
|
|
|
|
DECL_OPTION("-ftable", FOnOff, &m_fTable);
|
2021-03-26 14:48:24 +01:00
|
|
|
|
|
|
|
|
DECL_OPTION("-G", CbPartialMatch, [this](const char* optp) { addParameter(optp, false); });
|
|
|
|
|
DECL_OPTION("-gate-stmts", Set, &m_gateStmts);
|
|
|
|
|
DECL_OPTION("-gdb", CbCall, []() {}); // Processed only in bin/verilator shell
|
|
|
|
|
DECL_OPTION("-gdbbt", CbCall, []() {}); // Processed only in bin/verilator shell
|
|
|
|
|
DECL_OPTION("-generate-key", CbCall, [this]() {
|
|
|
|
|
cout << protectKeyDefaulted() << endl;
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(0);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
DECL_OPTION("-getenv", CbVal, [](const char* valp) {
|
|
|
|
|
cout << V3Options::getenvBuiltins(valp) << endl;
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(0);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-hierarchical", OnOff, &m_hierarchical);
|
|
|
|
|
DECL_OPTION("-hierarchical-block", CbVal, [this](const char* valp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const V3HierarchicalBlockOption opt(valp);
|
2021-03-26 14:48:24 +01:00
|
|
|
m_hierBlocks.emplace(opt.mangledName(), opt);
|
|
|
|
|
});
|
2022-07-18 16:32:14 +02:00
|
|
|
DECL_OPTION("-hierarchical-child", Set, &m_hierChild);
|
2021-03-26 14:48:24 +01:00
|
|
|
|
|
|
|
|
DECL_OPTION("-I", CbPartialMatch,
|
|
|
|
|
[this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); });
|
|
|
|
|
DECL_OPTION("-if-depth", Set, &m_ifDepth);
|
|
|
|
|
DECL_OPTION("-ignc", OnOff, &m_ignc);
|
|
|
|
|
DECL_OPTION("-inline-mult", Set, &m_inlineMult);
|
2021-07-25 17:10:55 +02:00
|
|
|
DECL_OPTION("-instr-count-dpi", CbVal, [this, fl](int val) {
|
|
|
|
|
m_instrCountDpi = val;
|
|
|
|
|
if (m_instrCountDpi < 0) fl->v3fatal("--instr-count-dpi must be non-negative: " << val);
|
|
|
|
|
});
|
2021-03-26 14:48:24 +01:00
|
|
|
|
2021-05-03 23:30:18 +02:00
|
|
|
DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs));
|
2021-06-21 00:32:57 +02:00
|
|
|
const auto setLang = [this, fl](const char* valp) {
|
2022-09-16 01:58:01 +02:00
|
|
|
const V3LangCode optval{valp};
|
2021-03-26 14:48:24 +01:00
|
|
|
if (optval.legal()) {
|
|
|
|
|
m_defaultLanguage = optval;
|
|
|
|
|
} else {
|
|
|
|
|
VSpellCheck spell;
|
|
|
|
|
for (int i = V3LangCode::L_ERROR + 1; i < V3LangCode::_ENUM_END; ++i) {
|
|
|
|
|
spell.pushCandidate(V3LangCode{i}.ascii());
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
fl->v3fatal("Unknown language specified: " << valp << spell.bestCandidateMsg(valp));
|
2020-04-15 01:55:00 +02:00
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
};
|
|
|
|
|
DECL_OPTION("-default-language", CbVal, setLang);
|
|
|
|
|
DECL_OPTION("-language", CbVal, setLang);
|
2021-11-14 15:39:31 +01:00
|
|
|
DECL_OPTION("-lib-create", Set, &m_libCreate);
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-lint-only", OnOff, &m_lintOnly);
|
|
|
|
|
DECL_OPTION("-l2-name", Set, &m_l2Name);
|
|
|
|
|
DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical
|
|
|
|
|
DECL_OPTION("-l2name", CbCall, [this]() { m_l2Name = "v"; }).undocumented(); // Historical
|
|
|
|
|
|
2021-05-03 23:30:18 +02:00
|
|
|
DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags));
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-MMD", OnOff, &m_makeDepend);
|
|
|
|
|
DECL_OPTION("-MP", OnOff, &m_makePhony);
|
|
|
|
|
DECL_OPTION("-Mdir", CbVal, [this](const char* valp) {
|
|
|
|
|
m_makeDir = valp;
|
|
|
|
|
addIncDirFallback(m_makeDir); // Need to find generated files there too
|
|
|
|
|
});
|
2022-09-15 02:18:40 +02:00
|
|
|
DECL_OPTION("-main", OnOff, &m_main);
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-make", CbVal, [this, fl](const char* valp) {
|
2022-09-15 03:10:19 +02:00
|
|
|
if (!std::strcmp(valp, "cmake")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_cmake = true;
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "gmake")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_gmake = true;
|
|
|
|
|
} else {
|
|
|
|
|
fl->v3fatal("Unknown --make system specified: '" << valp << "'");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-max-num-width", Set, &m_maxNumWidth);
|
|
|
|
|
DECL_OPTION("-mod-prefix", Set, &m_modPrefix);
|
|
|
|
|
|
2022-06-04 02:43:16 +02:00
|
|
|
DECL_OPTION("-O0", CbCall, [this]() { optimize(0); });
|
|
|
|
|
DECL_OPTION("-O1", CbCall, [this]() { optimize(1); });
|
|
|
|
|
DECL_OPTION("-O2", CbCall, [this]() { optimize(2); });
|
|
|
|
|
DECL_OPTION("-O3", CbCall, [this]() { optimize(3); });
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-O", CbPartialMatch, [this, fl](const char* optp) {
|
|
|
|
|
// Optimization, e.g. -O1rX
|
|
|
|
|
// LCOV_EXCL_START
|
|
|
|
|
fl->v3warn(DEPRECATED, "Option -O<letter> is deprecated. "
|
|
|
|
|
"Use -f<optimization> or -fno-<optimization> instead.");
|
2021-03-26 14:48:24 +01:00
|
|
|
for (const char* cp = optp; *cp; ++cp) {
|
|
|
|
|
const bool flag = isupper(*cp);
|
|
|
|
|
switch (tolower(*cp)) {
|
2022-06-04 02:43:16 +02:00
|
|
|
case '0': optimize(0); break;
|
|
|
|
|
case '1': optimize(1); break;
|
|
|
|
|
case '2': optimize(2); break;
|
|
|
|
|
case '3': optimize(3); break;
|
|
|
|
|
case 'a': m_fTable = flag; break; // == -fno-table
|
|
|
|
|
case 'b': m_fCombine = flag; break; // == -fno-combine
|
|
|
|
|
case 'c': m_fConst = flag; break; // == -fno-const
|
|
|
|
|
case 'd': m_fDedupe = flag; break; // == -fno-dedup
|
|
|
|
|
case 'e': m_fCase = flag; break; // == -fno-case
|
|
|
|
|
case 'g': m_fGate = flag; break; // == -fno-gate
|
|
|
|
|
case 'i': m_fInline = flag; break; // == -fno-inline
|
|
|
|
|
case 'k': m_fSubstConst = flag; break; // == -fno-subst-const
|
|
|
|
|
case 'l': m_fLife = flag; break; // == -fno-life
|
|
|
|
|
case 'm': m_fAssemble = flag; break; // == -fno-assemble
|
|
|
|
|
case 'o': m_fConstBitOpTree = flag; break; // == -fno-const-bit-op-tree
|
2021-03-26 14:48:24 +01:00
|
|
|
case 'p':
|
|
|
|
|
m_public = !flag;
|
|
|
|
|
break; // With -Op so flag=0, we want public on so few optimizations done
|
2022-06-04 02:43:16 +02:00
|
|
|
case 'r': m_fReorder = flag; break; // == -fno-reorder
|
|
|
|
|
case 's': m_fSplit = flag; break; // == -fno-split
|
|
|
|
|
case 't': m_fLifePost = flag; break; // == -fno-life-post
|
|
|
|
|
case 'u': m_fSubst = flag; break; // == -fno-subst
|
|
|
|
|
case 'v': m_fReloop = flag; break; // == -fno-reloop
|
|
|
|
|
case 'w': m_fMergeCond = flag; break; // == -fno-merge-cond
|
|
|
|
|
case 'x': m_fExpand = flag; break; // == -fno-expand
|
|
|
|
|
case 'y': m_fAcycSimp = flag; break; // == -fno-acyc-simp
|
|
|
|
|
case 'z': m_fLocalize = flag; break; // == -fno-localize
|
|
|
|
|
default:
|
|
|
|
|
break; // No error, just ignore
|
|
|
|
|
// LCOV_EXCL_STOP
|
2021-03-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-o", Set, &m_exeName);
|
2022-07-30 18:49:30 +02:00
|
|
|
DECL_OPTION("-order-clock-delay", CbOnOff, [fl](bool /*flag*/) {
|
2022-05-15 17:03:32 +02:00
|
|
|
fl->v3warn(DEPRECATED, "Option order-clock-delay is deprecated and has no effect.");
|
|
|
|
|
});
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-output-split", Set, &m_outputSplit);
|
|
|
|
|
DECL_OPTION("-output-split-cfuncs", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_outputSplitCFuncs = std::atoi(valp);
|
|
|
|
|
if (m_outputSplitCFuncs < 0) {
|
|
|
|
|
fl->v3error("--output-split-cfuncs must be >= 0: " << valp);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-output-split-ctrace", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_outputSplitCTrace = std::atoi(valp);
|
|
|
|
|
if (m_outputSplitCTrace < 0) {
|
|
|
|
|
fl->v3error("--output-split-ctrace must be >= 0: " << valp);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-P", Set, &m_preprocNoLine);
|
|
|
|
|
DECL_OPTION("-pvalue+", CbPartialMatch,
|
|
|
|
|
[this](const char* varp) { addParameter(varp, false); });
|
|
|
|
|
DECL_OPTION("-pins64", CbCall, [this]() { m_pinsBv = 65; });
|
|
|
|
|
DECL_OPTION("-no-pins64", CbCall, [this]() { m_pinsBv = 33; });
|
|
|
|
|
DECL_OPTION("-pins-bv", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_pinsBv = std::atoi(valp);
|
|
|
|
|
if (m_pinsBv > 65) fl->v3fatal("--pins-bv maximum is 65: " << valp);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-pins-sc-uint", CbOnOff, [this](bool flag) {
|
|
|
|
|
m_pinsScUint = flag;
|
|
|
|
|
if (!m_pinsScBigUint) m_pinsBv = 65;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-pins-sc-biguint", CbOnOff, [this](bool flag) {
|
|
|
|
|
m_pinsScBigUint = flag;
|
|
|
|
|
m_pinsBv = 513;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8);
|
|
|
|
|
DECL_OPTION("-pipe-filter", Set, &m_pipeFilter);
|
|
|
|
|
DECL_OPTION("-pp-comments", OnOff, &m_ppComments);
|
2022-09-12 18:21:27 +02:00
|
|
|
DECL_OPTION("-prefix", Set, &m_prefix);
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-private", CbCall, [this]() { m_public = false; });
|
2021-07-08 01:12:52 +02:00
|
|
|
DECL_OPTION("-prof-c", OnOff, &m_profC);
|
|
|
|
|
DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; });
|
|
|
|
|
DECL_OPTION("-profile-cfuncs", CbCall,
|
|
|
|
|
[this]() { m_profC = m_profCFuncs = true; }); // Renamed
|
2022-03-25 20:46:50 +01:00
|
|
|
DECL_OPTION("-prof-exec", OnOff, &m_profExec);
|
|
|
|
|
DECL_OPTION("-prof-pgo", OnOff, &m_profPgo);
|
|
|
|
|
DECL_OPTION("-prof-threads", CbOnOff, [this, fl](bool flag) {
|
|
|
|
|
fl->v3warn(DEPRECATED, "Option --prof-threads is deprecated. "
|
|
|
|
|
"Use --prof-exec and --prof-pgo instead.");
|
|
|
|
|
m_profExec = m_profPgo = flag;
|
|
|
|
|
});
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-protect-ids", OnOff, &m_protectIds);
|
|
|
|
|
DECL_OPTION("-protect-key", Set, &m_protectKey);
|
|
|
|
|
DECL_OPTION("-protect-lib", CbVal, [this](const char* valp) {
|
2021-11-14 15:39:31 +01:00
|
|
|
m_libCreate = valp;
|
2021-03-26 14:48:24 +01:00
|
|
|
m_protectIds = true;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-public", OnOff, &m_public);
|
|
|
|
|
DECL_OPTION("-public-flat-rw", CbOnOff, [this](bool flag) {
|
|
|
|
|
m_publicFlatRW = flag;
|
|
|
|
|
v3Global.dpi(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-quiet-exit", OnOff, &m_quietExit);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes);
|
2021-05-15 19:04:40 +02:00
|
|
|
DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_reloopLimit = std::atoi(valp);
|
|
|
|
|
if (m_reloopLimit < 2) { fl->v3error("--reloop-limit must be >= 2: " << valp); }
|
|
|
|
|
});
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-report-unoptflat", OnOff, &m_reportUnoptflat);
|
|
|
|
|
DECL_OPTION("-rr", CbCall, []() {}); // Processed only in bin/verilator shell
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-savable", OnOff, &m_savable);
|
|
|
|
|
DECL_OPTION("-sc", CbCall, [this]() {
|
|
|
|
|
m_outFormatOk = true;
|
|
|
|
|
m_systemC = true;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-skip-identical", OnOff, &m_skipIdentical);
|
|
|
|
|
DECL_OPTION("-stats", OnOff, &m_stats);
|
|
|
|
|
DECL_OPTION("-stats-vars", CbOnOff, [this](bool flag) {
|
|
|
|
|
m_statsVars = flag;
|
|
|
|
|
m_stats |= flag;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-structs-unpacked", OnOff, &m_structsPacked);
|
|
|
|
|
DECL_OPTION("-sv", CbCall, [this]() { m_defaultLanguage = V3LangCode::L1800_2017; });
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-threads-coarsen", OnOff, &m_threadsCoarsen).undocumented(); // Debug
|
|
|
|
|
DECL_OPTION("-no-threads", CbCall, [this]() { m_threads = 0; });
|
|
|
|
|
DECL_OPTION("-threads", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_threads = std::atoi(valp);
|
|
|
|
|
if (m_threads < 0) fl->v3fatal("--threads must be >= 0: " << valp);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) {
|
2022-09-15 03:10:19 +02:00
|
|
|
if (!std::strcmp(valp, "all")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_threadsDpiPure = true;
|
|
|
|
|
m_threadsDpiUnpure = true;
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "none")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_threadsDpiPure = false;
|
|
|
|
|
m_threadsDpiUnpure = false;
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "pure")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_threadsDpiPure = true;
|
|
|
|
|
m_threadsDpiUnpure = false;
|
|
|
|
|
} else {
|
2021-03-27 18:14:43 +01:00
|
|
|
fl->v3fatal("Unknown setting for --threads-dpi: '"
|
|
|
|
|
<< valp << "'\n"
|
|
|
|
|
<< fl->warnMore() << "... Suggest 'all', 'none', or 'pure'");
|
2021-03-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-threads-max-mtasks", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_threadsMaxMTasks = std::atoi(valp);
|
|
|
|
|
if (m_threadsMaxMTasks < 1) fl->v3fatal("--threads-max-mtasks must be >= 1: " << valp);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-timescale", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
VTimescale unit;
|
|
|
|
|
VTimescale prec;
|
|
|
|
|
VTimescale::parseSlashed(fl, valp, unit /*ref*/, prec /*ref*/);
|
|
|
|
|
if (!unit.isNone() && timeOverrideUnit().isNone()) m_timeDefaultUnit = unit;
|
|
|
|
|
if (!prec.isNone() && timeOverridePrec().isNone()) m_timeDefaultPrec = prec;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-timescale-override", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
VTimescale unit;
|
|
|
|
|
VTimescale prec;
|
|
|
|
|
VTimescale::parseSlashed(fl, valp, unit /*ref*/, prec /*ref*/, true);
|
|
|
|
|
if (!unit.isNone()) {
|
|
|
|
|
m_timeDefaultUnit = unit;
|
|
|
|
|
m_timeOverrideUnit = unit;
|
|
|
|
|
}
|
|
|
|
|
if (!prec.isNone()) {
|
|
|
|
|
m_timeDefaultPrec = prec;
|
|
|
|
|
m_timeOverridePrec = prec;
|
|
|
|
|
}
|
|
|
|
|
});
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
DECL_OPTION("-timing", OnOff, &m_timing);
|
2021-03-26 14:48:24 +01:00
|
|
|
DECL_OPTION("-top-module", Set, &m_topModule);
|
|
|
|
|
DECL_OPTION("-top", Set, &m_topModule);
|
|
|
|
|
DECL_OPTION("-trace", OnOff, &m_trace);
|
|
|
|
|
DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage);
|
|
|
|
|
DECL_OPTION("-trace-depth", Set, &m_traceDepth);
|
|
|
|
|
DECL_OPTION("-trace-fst", CbCall, [this]() {
|
|
|
|
|
m_trace = true;
|
|
|
|
|
m_traceFormat = TraceFormat::FST;
|
|
|
|
|
addLdLibs("-lz");
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-trace-fst-thread", CbCall, [this, fl]() {
|
|
|
|
|
m_trace = true;
|
|
|
|
|
m_traceFormat = TraceFormat::FST;
|
|
|
|
|
addLdLibs("-lz");
|
|
|
|
|
fl->v3warn(DEPRECATED, "Option --trace-fst-thread is deprecated. "
|
|
|
|
|
"Use --trace-fst with --trace-threads > 0.");
|
|
|
|
|
if (m_traceThreads == 0) m_traceThreads = 1;
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-trace-max-array", Set, &m_traceMaxArray);
|
|
|
|
|
DECL_OPTION("-trace-max-width", Set, &m_traceMaxWidth);
|
|
|
|
|
DECL_OPTION("-trace-params", OnOff, &m_traceParams);
|
|
|
|
|
DECL_OPTION("-trace-structs", OnOff, &m_traceStructs);
|
|
|
|
|
DECL_OPTION("-trace-threads", CbVal, [this, fl](const char* valp) {
|
|
|
|
|
m_trace = true;
|
|
|
|
|
m_traceThreads = std::atoi(valp);
|
2022-05-29 20:08:39 +02:00
|
|
|
if (m_traceThreads < 1) fl->v3fatal("--trace-threads must be >= 1: " << valp);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
DECL_OPTION("-trace-underscore", OnOff, &m_traceUnderscore);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-U", CbPartialMatch, &V3PreShell::undef);
|
|
|
|
|
DECL_OPTION("-underline-zero", OnOff, &m_underlineZero); // Deprecated
|
|
|
|
|
DECL_OPTION("-unroll-count", Set, &m_unrollCount).undocumented(); // Optimization tweak
|
|
|
|
|
DECL_OPTION("-unroll-stmts", Set, &m_unrollStmts).undocumented(); // Optimization tweak
|
|
|
|
|
DECL_OPTION("-unused-regexp", Set, &m_unusedRegexp);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-V", CbCall, [this]() {
|
|
|
|
|
showVersion(true);
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(0);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) {
|
|
|
|
|
V3Options::addLibraryFile(parseFileArg(optdir, valp));
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-verilate", OnOff, &m_verilate);
|
|
|
|
|
DECL_OPTION("-version", CbCall, [this]() {
|
|
|
|
|
showVersion(false);
|
2021-03-27 02:23:18 +01:00
|
|
|
std::exit(0);
|
2021-03-26 14:48:24 +01:00
|
|
|
});
|
|
|
|
|
DECL_OPTION("-vpi", OnOff, &m_vpi);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-Wpedantic", OnOff, &m_pedantic);
|
|
|
|
|
DECL_OPTION("-Wall", CbCall, []() {
|
|
|
|
|
FileLine::globalWarnLintOff(false);
|
|
|
|
|
FileLine::globalWarnStyleOff(false);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-Werror-", CbPartialMatch, [this, fl](const char* optp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const V3ErrorCode code(optp);
|
2021-03-26 14:48:24 +01:00
|
|
|
if (code == V3ErrorCode::EC_ERROR) {
|
|
|
|
|
if (!isFuture(optp)) fl->v3fatal("Unknown warning specified: -Werror-" << optp);
|
|
|
|
|
} else {
|
|
|
|
|
V3Error::pretendError(code, true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-Wfuture-", CbPartialMatch, [this](const char* optp) {
|
|
|
|
|
// Note it may not be a future option, but one that is currently implemented.
|
|
|
|
|
addFuture(optp);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-Wno-", CbPartialMatch, [fl, &parser](const char* optp) {
|
|
|
|
|
if (!FileLine::globalWarnOff(optp, true)) {
|
2022-08-30 05:50:32 +02:00
|
|
|
const string fullopt = std::string{"-Wno-"} + optp;
|
2021-03-26 14:48:24 +01:00
|
|
|
fl->v3fatal("Unknown warning specified: " << fullopt
|
|
|
|
|
<< parser.getSuggestion(fullopt.c_str()));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
for (int i = V3ErrorCode::EC_FIRST_WARN; i < V3ErrorCode::_ENUM_MAX; ++i) {
|
|
|
|
|
for (const string prefix : {"-Wno-", "-Wwarn-"})
|
|
|
|
|
parser.addSuggestionCandidate(prefix + V3ErrorCode{i}.ascii());
|
|
|
|
|
}
|
|
|
|
|
DECL_OPTION("-Wno-context", CbCall, [this]() { m_context = false; });
|
|
|
|
|
DECL_OPTION("-Wno-fatal", CbCall, []() { V3Error::warnFatal(false); });
|
|
|
|
|
DECL_OPTION("-Wno-lint", CbCall, []() {
|
|
|
|
|
FileLine::globalWarnLintOff(true);
|
|
|
|
|
FileLine::globalWarnStyleOff(true);
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); });
|
|
|
|
|
DECL_OPTION("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) {
|
|
|
|
|
const V3ErrorCode code{optp};
|
|
|
|
|
if (code == V3ErrorCode::EC_ERROR) {
|
|
|
|
|
if (!isFuture(optp)) {
|
2022-08-30 05:50:32 +02:00
|
|
|
const string fullopt = std::string{"-Wwarn-"} + optp;
|
2021-03-26 14:48:24 +01:00
|
|
|
fl->v3fatal("Unknown warning specified: "
|
|
|
|
|
<< fullopt << parser.getSuggestion(fullopt.c_str()));
|
2020-06-09 04:17:30 +02:00
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
} else {
|
|
|
|
|
FileLine::globalWarnOff(code, false);
|
|
|
|
|
V3Error::pretendError(code, false);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-Wwarn-lint", CbCall, []() { FileLine::globalWarnLintOff(false); });
|
|
|
|
|
DECL_OPTION("-Wwarn-style", CbCall, []() { FileLine::globalWarnStyleOff(false); });
|
|
|
|
|
DECL_OPTION("-waiver-output", Set, &m_waiverOutput);
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) {
|
2022-09-15 03:10:19 +02:00
|
|
|
if (!std::strcmp(valp, "0")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xAssign = "0";
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "1")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xAssign = "1";
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "fast")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xAssign = "fast";
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "unique")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xAssign = "unique";
|
|
|
|
|
} else {
|
2021-03-27 18:14:43 +01:00
|
|
|
fl->v3fatal("Unknown setting for --x-assign: '"
|
|
|
|
|
<< valp << "'\n"
|
|
|
|
|
<< fl->warnMore() << "... Suggest '0', '1', 'fast', or 'unique'");
|
2021-03-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) {
|
2022-09-15 03:10:19 +02:00
|
|
|
if (!std::strcmp(valp, "0")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xInitial = "0";
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "fast")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xInitial = "fast";
|
2022-09-15 03:10:19 +02:00
|
|
|
} else if (!std::strcmp(valp, "unique")) {
|
2021-03-26 14:48:24 +01:00
|
|
|
m_xInitial = "unique";
|
|
|
|
|
} else {
|
2021-03-27 18:14:43 +01:00
|
|
|
fl->v3fatal("Unknown setting for --x-initial: '"
|
|
|
|
|
<< valp << "'\n"
|
|
|
|
|
<< fl->warnMore() << "... Suggest '0', 'fast', or 'unique'");
|
2021-03-26 14:48:24 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
DECL_OPTION("-x-initial-edge", OnOff, &m_xInitialEdge);
|
|
|
|
|
DECL_OPTION("-xml-only", OnOff, &m_xmlOnly);
|
|
|
|
|
DECL_OPTION("-xml-output", CbVal, [this](const char* valp) {
|
|
|
|
|
m_xmlOutput = valp;
|
|
|
|
|
m_xmlOnly = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
DECL_OPTION("-y", CbVal, [this, &optdir](const char* valp) {
|
|
|
|
|
addIncDirUser(parseFileArg(optdir, string(valp)));
|
|
|
|
|
});
|
|
|
|
|
parser.finalize();
|
2020-04-15 01:55:00 +02:00
|
|
|
|
2021-03-26 14:48:24 +01:00
|
|
|
for (int i = 0; i < argc;) {
|
|
|
|
|
UINFO(9, " Option: " << argv[i] << endl);
|
2022-09-15 03:10:19 +02:00
|
|
|
if (!std::strcmp(argv[i], "-j")
|
|
|
|
|
|| !std::strcmp(argv[i], "--j")) { // Allow gnu -- switches
|
2021-03-26 14:48:24 +01:00
|
|
|
++i;
|
2022-09-15 14:28:58 +02:00
|
|
|
int val = 0;
|
2021-03-26 14:48:24 +01:00
|
|
|
if (i < argc && isdigit(argv[i][0])) {
|
2022-09-15 14:28:58 +02:00
|
|
|
val = atoi(argv[i]);
|
|
|
|
|
if (val < 0) {
|
|
|
|
|
fl->v3error("-j requires a non-negative integer argument, but '"
|
|
|
|
|
<< argv[i] << "' was passed");
|
|
|
|
|
val = 1; // Fall-back value, though we will exit on error.
|
|
|
|
|
} else if (val == 0) {
|
|
|
|
|
val = std::thread::hardware_concurrency();
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
++i;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-09-15 14:28:58 +02:00
|
|
|
if (m_buildJobs == -1) m_buildJobs = val;
|
2021-03-26 14:48:24 +01:00
|
|
|
} else if (argv[i][0] == '-' || argv[i][0] == '+') {
|
2022-08-20 20:01:13 +02:00
|
|
|
const char* argvNoDashp = (argv[i][1] == '-') ? (argv[i] + 2) : (argv[i] + 1);
|
2021-03-26 14:48:24 +01:00
|
|
|
if (const int consumed = parser.parse(i, argc, argv)) {
|
|
|
|
|
i += consumed;
|
2022-08-20 20:01:13 +02:00
|
|
|
} else if (isFuture0(argvNoDashp)) {
|
|
|
|
|
++i;
|
|
|
|
|
} else if (isFuture1(argvNoDashp)) {
|
|
|
|
|
i += 2;
|
2020-04-15 01:55:00 +02:00
|
|
|
} else {
|
2021-03-26 14:48:24 +01:00
|
|
|
fl->v3fatal("Invalid option: " << argv[i] << parser.getSuggestion(argv[i]));
|
2021-07-10 00:11:59 +02:00
|
|
|
++i; // LCOV_EXCL_LINE
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Filename
|
2021-06-21 00:32:57 +02:00
|
|
|
const string filename = parseFileArg(optdir, argv[i]);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (suffixed(filename, ".cpp") //
|
|
|
|
|
|| suffixed(filename, ".cxx") //
|
|
|
|
|
|| suffixed(filename, ".cc") //
|
|
|
|
|
|| suffixed(filename, ".c") //
|
2019-05-19 22:13:13 +02:00
|
|
|
|| suffixed(filename, ".sp")) {
|
|
|
|
|
V3Options::addCppFile(filename);
|
2020-04-15 01:55:00 +02:00
|
|
|
} else if (suffixed(filename, ".a") //
|
|
|
|
|
|| suffixed(filename, ".o") //
|
|
|
|
|
|| suffixed(filename, ".so")) {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Options::addLdLibs(filename);
|
2020-04-15 01:55:00 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
V3Options::addVFile(filename);
|
|
|
|
|
}
|
2021-03-26 14:48:24 +01:00
|
|
|
++i;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-15 14:28:58 +02:00
|
|
|
if (m_buildJobs == -1) m_buildJobs = 1;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
2010-11-03 12:02:32 +01:00
|
|
|
void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
|
2006-08-26 13:35:28 +02:00
|
|
|
// Read the specified -f filename and process as arguments
|
2020-04-15 01:55:00 +02:00
|
|
|
UINFO(1, "Reading Options File " << filename << endl);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-07-12 00:42:01 +02:00
|
|
|
const std::unique_ptr<std::ifstream> ifp{V3File::new_ifstream(filename)};
|
2006-08-26 13:35:28 +02:00
|
|
|
if (ifp->fail()) {
|
2020-04-15 01:55:00 +02:00
|
|
|
fl->v3error("Cannot open -f command file: " + filename);
|
2019-05-19 22:13:13 +02:00
|
|
|
return;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string whole_file;
|
2008-04-24 17:36:46 +02:00
|
|
|
bool inCmt = false;
|
2006-08-26 13:35:28 +02:00
|
|
|
while (!ifp->eof()) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string line = V3Os::getline(*ifp);
|
2018-11-27 01:09:08 +01:00
|
|
|
// Strip simple comments
|
|
|
|
|
string oline;
|
2019-05-19 22:13:13 +02:00
|
|
|
// cppcheck-suppress StlMissingComparison
|
2019-11-21 03:23:03 +01:00
|
|
|
char lastch = ' ';
|
2020-09-16 02:12:08 +02:00
|
|
|
bool space_begin = true; // At beginning or leading spaces only
|
2019-11-21 03:23:03 +01:00
|
|
|
for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (inCmt) {
|
2020-04-15 01:55:00 +02:00
|
|
|
if (*pos == '*' && *(pos + 1) == '/') {
|
2019-05-19 22:13:13 +02:00
|
|
|
inCmt = false;
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
} else if (*pos == '/' && *(pos + 1) == '/'
|
|
|
|
|
&& (pos == line.begin() || isspace(lastch))) { // But allow /file//path
|
2019-05-19 22:13:13 +02:00
|
|
|
break; // Ignore to EOL
|
2020-09-16 02:12:08 +02:00
|
|
|
} else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line
|
|
|
|
|
break; // Ignore to EOL
|
2020-04-15 01:55:00 +02:00
|
|
|
} else if (*pos == '/' && *(pos + 1) == '*') {
|
2019-05-19 22:13:13 +02:00
|
|
|
inCmt = true;
|
2020-09-16 02:12:08 +02:00
|
|
|
space_begin = false;
|
2019-05-19 22:13:13 +02:00
|
|
|
// cppcheck-suppress StlMissingComparison
|
|
|
|
|
++pos;
|
|
|
|
|
} else {
|
2020-09-16 02:12:08 +02:00
|
|
|
if (!isspace(*pos)) space_begin = false;
|
2019-05-19 22:13:13 +02:00
|
|
|
oline += *pos;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
whole_file += oline + " ";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
whole_file += "\n"; // So string match below is simplified
|
2008-04-24 17:36:46 +02:00
|
|
|
if (inCmt) fl->v3error("Unterminated /* comment inside -f file.");
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2019-07-11 04:04:58 +02:00
|
|
|
fl = new FileLine(filename);
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Split into argument list and process
|
2019-10-24 13:33:19 +02:00
|
|
|
// Note we try to respect escaped char, double/simple quoted strings
|
|
|
|
|
// Other simulators don't respect a common syntax...
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Strip off arguments and parse into words
|
2018-02-02 03:24:41 +01:00
|
|
|
std::vector<string> args;
|
2019-10-24 13:33:19 +02:00
|
|
|
|
|
|
|
|
// Parse file using a state machine, taking into account quoted strings and escaped chars
|
2020-08-16 18:05:35 +02:00
|
|
|
enum state : uint8_t {
|
|
|
|
|
ST_IN_OPTION,
|
|
|
|
|
ST_ESCAPED_CHAR,
|
|
|
|
|
ST_IN_QUOTED_STR,
|
|
|
|
|
ST_IN_DOUBLE_QUOTED_STR
|
|
|
|
|
};
|
2019-10-24 13:33:19 +02:00
|
|
|
|
|
|
|
|
state st = ST_IN_OPTION;
|
2019-11-10 00:42:18 +01:00
|
|
|
state last_st = ST_IN_OPTION;
|
2019-10-24 13:33:19 +02:00
|
|
|
string arg;
|
2020-04-15 01:55:00 +02:00
|
|
|
for (string::size_type pos = 0; pos < whole_file.length(); ++pos) {
|
2019-10-24 13:33:19 +02:00
|
|
|
char curr_char = whole_file[pos];
|
|
|
|
|
switch (st) {
|
|
|
|
|
case ST_IN_OPTION: // Get all chars up to a white space or a "="
|
|
|
|
|
if (isspace(curr_char)) { // End of option
|
|
|
|
|
if (!arg.empty()) { // End of word
|
|
|
|
|
args.push_back(arg);
|
|
|
|
|
}
|
|
|
|
|
arg = "";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (curr_char == '\\') { // Escape char, we wait for next char
|
|
|
|
|
last_st = st; // Memorize current state
|
|
|
|
|
st = ST_ESCAPED_CHAR;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (curr_char == '\'') { // Find begin of quoted string
|
|
|
|
|
// Examine next char in order to decide between
|
|
|
|
|
// a string or a base specifier for integer literal
|
|
|
|
|
++pos;
|
|
|
|
|
if (pos < whole_file.length()) curr_char = whole_file[pos];
|
|
|
|
|
if (curr_char == '"') { // String
|
|
|
|
|
st = ST_IN_QUOTED_STR;
|
|
|
|
|
} else { // Base specifier
|
|
|
|
|
arg += '\'';
|
|
|
|
|
}
|
2020-04-15 01:55:00 +02:00
|
|
|
arg += curr_char;
|
2019-10-24 13:33:19 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (curr_char == '"') { // Find begin of double quoted string
|
|
|
|
|
// Doesn't insert the quote
|
|
|
|
|
st = ST_IN_DOUBLE_QUOTED_STR;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
arg += curr_char;
|
|
|
|
|
break;
|
|
|
|
|
case ST_IN_QUOTED_STR: // Just store all chars inside string
|
|
|
|
|
if (curr_char != '\'') {
|
|
|
|
|
arg += curr_char;
|
|
|
|
|
} else { // End of quoted string
|
|
|
|
|
st = ST_IN_OPTION;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ST_IN_DOUBLE_QUOTED_STR: // Take into account escaped chars
|
|
|
|
|
if (curr_char != '"') {
|
|
|
|
|
if (curr_char == '\\') {
|
|
|
|
|
last_st = st;
|
|
|
|
|
st = ST_ESCAPED_CHAR;
|
|
|
|
|
} else {
|
|
|
|
|
arg += curr_char;
|
|
|
|
|
}
|
|
|
|
|
} else { // End of double quoted string
|
|
|
|
|
st = ST_IN_OPTION;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ST_ESCAPED_CHAR: // Just add the escaped char
|
|
|
|
|
arg += curr_char;
|
|
|
|
|
st = last_st;
|
|
|
|
|
break;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2019-10-24 13:33:19 +02:00
|
|
|
}
|
|
|
|
|
if (!arg.empty()) { // Add last word
|
|
|
|
|
args.push_back(arg);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-03 12:02:32 +01:00
|
|
|
// Path
|
2021-06-21 00:32:57 +02:00
|
|
|
const string optdir = (rel ? V3Os::filenameDir(filename) : ".");
|
2010-11-03 12:02:32 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Convert to argv style arg list and parse them
|
2020-04-15 01:55:00 +02:00
|
|
|
std::vector<char*> argv;
|
|
|
|
|
argv.reserve(args.size() + 1);
|
2020-08-16 18:54:32 +02:00
|
|
|
for (const string& i : args) argv.push_back(const_cast<char*>(i.c_str()));
|
2020-08-15 16:12:55 +02:00
|
|
|
argv.push_back(nullptr); // argv is nullptr-terminated
|
2020-04-15 01:55:00 +02:00
|
|
|
parseOptsList(fl, optdir, static_cast<int>(argv.size() - 1), argv.data());
|
2010-11-03 12:02:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
|
|
string V3Options::parseFileArg(const string& optdir, const string& relfilename) {
|
2015-02-27 02:40:45 +01:00
|
|
|
string filename = V3Os::filenameSubstitute(relfilename);
|
2020-04-15 01:55:00 +02:00
|
|
|
if (optdir != "." && V3Os::filenameIsRel(filename)) filename = optdir + "/" + filename;
|
2010-11-03 12:02:32 +01:00
|
|
|
return filename;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
2012-11-14 02:12:23 +01:00
|
|
|
|
2009-06-26 01:53:26 +02:00
|
|
|
void V3Options::showVersion(bool verbose) {
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << version();
|
|
|
|
|
cout << endl;
|
2009-06-26 01:53:26 +02:00
|
|
|
if (!verbose) return;
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << endl;
|
2022-01-01 14:26:40 +01:00
|
|
|
cout << "Copyright 2003-2022 by Wilson Snyder. Verilator is free software; you can\n";
|
2009-06-26 01:53:26 +02:00
|
|
|
cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
|
|
|
|
|
cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
|
|
|
|
|
cout << "License Version 2.0.\n";
|
|
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << endl;
|
2019-11-08 04:41:34 +01:00
|
|
|
cout << "See https://verilator.org for documentation\n";
|
2009-06-26 01:53:26 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << endl;
|
2009-06-26 01:53:26 +02:00
|
|
|
cout << "Summary of configuration:\n";
|
|
|
|
|
cout << " Compiled in defaults if not in environment:\n";
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << " SYSTEMC = " << DEFENV_SYSTEMC << endl;
|
|
|
|
|
cout << " SYSTEMC_ARCH = " << DEFENV_SYSTEMC_ARCH << endl;
|
|
|
|
|
cout << " SYSTEMC_INCLUDE = " << DEFENV_SYSTEMC_INCLUDE << endl;
|
|
|
|
|
cout << " SYSTEMC_LIBDIR = " << DEFENV_SYSTEMC_LIBDIR << endl;
|
|
|
|
|
cout << " VERILATOR_ROOT = " << DEFENV_VERILATOR_ROOT << endl;
|
2020-05-29 00:51:46 +02:00
|
|
|
cout << " SystemC system-wide = " << cvtToStr(systemCSystemWide()) << endl;
|
2009-06-26 01:53:26 +02:00
|
|
|
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << endl;
|
2009-06-26 01:53:26 +02:00
|
|
|
cout << "Environment:\n";
|
2020-04-15 23:44:21 +02:00
|
|
|
cout << " MAKE = " << V3Os::getenvStr("MAKE", "") << endl;
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << " PERL = " << V3Os::getenvStr("PERL", "") << endl;
|
|
|
|
|
cout << " SYSTEMC = " << V3Os::getenvStr("SYSTEMC", "") << endl;
|
|
|
|
|
cout << " SYSTEMC_ARCH = " << V3Os::getenvStr("SYSTEMC_ARCH", "") << endl;
|
|
|
|
|
cout << " SYSTEMC_INCLUDE = " << V3Os::getenvStr("SYSTEMC_INCLUDE", "") << endl;
|
|
|
|
|
cout << " SYSTEMC_LIBDIR = " << V3Os::getenvStr("SYSTEMC_LIBDIR", "") << endl;
|
2022-09-17 14:17:47 +02:00
|
|
|
// wrapper uses VERILATOR_BIN
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << " VERILATOR_BIN = " << V3Os::getenvStr("VERILATOR_BIN", "") << endl;
|
2022-09-17 14:17:47 +02:00
|
|
|
cout << " VERILATOR_ROOT = " << V3Os::getenvStr("VERILATOR_ROOT", "") << endl;
|
2020-05-29 00:51:46 +02:00
|
|
|
|
|
|
|
|
cout << endl;
|
|
|
|
|
cout << "Features (based on environment or compiled-in support):\n";
|
|
|
|
|
cout << " SystemC found = " << cvtToStr(systemCFound()) << endl;
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 14:26:32 +02:00
|
|
|
cout << " Coroutine support = " << cvtToStr(coroutineSupport()) << endl;
|
2009-06-26 01:53:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
V3Options::V3Options() {
|
|
|
|
|
m_impp = new V3OptionsImp;
|
|
|
|
|
|
2019-10-27 14:27:18 +01:00
|
|
|
m_traceFormat = TraceFormat::VCD;
|
2007-04-19 20:20:16 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
m_makeDir = "obj_dir";
|
2011-01-02 01:43:22 +01:00
|
|
|
m_unusedRegexp = "*unused*";
|
2008-07-16 19:31:21 +02:00
|
|
|
m_xAssign = "fast";
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2012-11-14 02:12:23 +01:00
|
|
|
m_defaultLanguage = V3LangCode::mostRecent();
|
2008-03-28 21:41:21 +01:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
VName::maxLength(128); // Linux filename limits 256; leave half for prefix
|
2015-09-20 02:12:35 +02:00
|
|
|
|
2018-02-27 13:16:16 +01:00
|
|
|
optimize(1);
|
2006-08-26 13:35:28 +02:00
|
|
|
// Default +libext+
|
2012-02-12 02:40:58 +01:00
|
|
|
addLibExtV(""); // So include "filename.v" will find the same file
|
|
|
|
|
addLibExtV(".v");
|
|
|
|
|
addLibExtV(".sv");
|
2006-08-26 13:35:28 +02:00
|
|
|
// Default -I
|
2019-05-19 22:13:13 +02:00
|
|
|
addIncDirFallback("."); // Looks better than {long_cwd_path}/...
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-15 16:12:55 +02:00
|
|
|
V3Options::~V3Options() { VL_DO_CLEAR(delete m_impp, m_impp = nullptr); }
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
void V3Options::setDebugMode(int level) {
|
|
|
|
|
V3Error::debugDefault(level);
|
2022-09-18 21:53:42 +02:00
|
|
|
if (!m_dumpLevel.count("tree")) m_dumpLevel["tree"] = 3; // Don't override if already set.
|
2006-08-26 13:35:28 +02:00
|
|
|
m_stats = true;
|
2006-10-02 19:09:56 +02:00
|
|
|
m_debugCheck = true;
|
2020-04-15 01:55:00 +02:00
|
|
|
cout << "Starting " << version() << endl;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
unsigned V3Options::debugLevel(const string& tag) const {
|
|
|
|
|
const auto iter = m_debugLevel.find(tag);
|
|
|
|
|
return iter != m_debugLevel.end() ? iter->second : V3Error::debugDefault();
|
2009-01-21 22:56:50 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
unsigned V3Options::debugSrcLevel(const string& srcfile_path) const {
|
2009-01-21 22:56:50 +01:00
|
|
|
// For simplicity, calling functions can just use __FILE__ for srcfile.
|
2022-09-18 21:53:42 +02:00
|
|
|
// That means we need to strip the filenames: ../Foo.cpp -> Foo
|
|
|
|
|
return debugLevel(V3Os::filenameNonDirExt(srcfile_path));
|
2009-01-21 22:56:50 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
unsigned V3Options::dumpLevel(const string& tag) const {
|
|
|
|
|
const auto iter = m_dumpLevel.find(tag);
|
|
|
|
|
return iter != m_dumpLevel.end() ? iter->second : 0;
|
2015-03-13 00:47:54 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
unsigned V3Options::dumpSrcLevel(const string& srcfile_path) const {
|
2015-03-13 00:47:54 +01:00
|
|
|
// For simplicity, calling functions can just use __FILE__ for srcfile.
|
2022-09-18 21:53:42 +02:00
|
|
|
// That means we need to strip the filenames: ../Foo.cpp -> Foo
|
|
|
|
|
return dumpLevel(V3Os::filenameNonDirExt(srcfile_path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool V3Options::dumpTreeAddrids() const {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) {
|
|
|
|
|
const unsigned value = dumpLevel("tree-addrids");
|
|
|
|
|
if (!available()) return value > 0;
|
|
|
|
|
level = static_cast<unsigned>(value);
|
2015-03-13 00:47:54 +01:00
|
|
|
}
|
2022-09-18 21:53:42 +02:00
|
|
|
return level > 0;
|
2015-03-13 00:47:54 +01:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
void V3Options::optimize(int level) {
|
|
|
|
|
// Set all optimizations to on/off
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool flag = level > 0;
|
2022-06-04 02:43:16 +02:00
|
|
|
m_fAcycSimp = flag;
|
|
|
|
|
m_fAssemble = flag;
|
|
|
|
|
m_fCase = flag;
|
|
|
|
|
m_fCombine = flag;
|
|
|
|
|
m_fConst = flag;
|
|
|
|
|
m_fConstBitOpTree = flag;
|
|
|
|
|
m_fDedupe = flag;
|
Introduce DFG based combinational logic optimizer (#3527)
Added a new data-flow graph (DFG) based combinational logic optimizer.
The capabilities of this covers a combination of V3Const and V3Gate, but
is also more capable of transforming combinational logic into simplified
forms and more.
This entail adding a new internal representation, `DfgGraph`, and
appropriate `astToDfg` and `dfgToAst` conversion functions. The graph
represents some of the combinational equations (~continuous assignments)
in a module, and for the duration of the DFG passes, it takes over the
role of AstModule. A bulk of the Dfg vertices represent expressions.
These vertex classes, and the corresponding conversions to/from AST are
mostly auto-generated by astgen, together with a DfgVVisitor that can be
used for dynamic dispatch based on vertex (operation) types.
The resulting combinational logic graph (a `DfgGraph`) is then optimized
in various ways. Currently we perform common sub-expression elimination,
variable inlining, and some specific peephole optimizations, but there
is scope for more optimizations in the future using the same
representation. The optimizer is run directly before and after inlining.
The pre inline pass can operate on smaller graphs and hence converges
faster, but still has a chance of substantially reducing the size of the
logic on some designs, making inlining both faster and less memory
intensive. The post inline pass can then optimize across the inlined
module boundaries. No optimization is performed across a module
boundary.
For debugging purposes, each peephole optimization can be disabled
individually via the -fno-dfg-peepnole-<OPT> option, where <OPT> is one
of the optimizations listed in V3DfgPeephole.h, for example
-fno-dfg-peephole-remove-not-not.
The peephole patterns currently implemented were mostly picked based on
the design that inspired this work, and on that design the optimizations
yields ~30% single threaded speedup, and ~50% speedup on 4 threads. As
you can imagine not having to haul around redundant combinational
networks in the rest of the compilation pipeline also helps with memory
consumption, and up to 30% peak memory usage of Verilator was observed
on the same design.
Gains on other arbitrary designs are smaller (and can be improved by
analyzing those designs). For example OpenTitan gains between 1-15%
speedup depending on build type.
2022-09-23 17:46:22 +02:00
|
|
|
m_fDfgPreInline = flag;
|
|
|
|
|
m_fDfgPostInline = flag;
|
2022-06-04 02:43:16 +02:00
|
|
|
m_fExpand = flag;
|
|
|
|
|
m_fGate = flag;
|
|
|
|
|
m_fInline = flag;
|
|
|
|
|
m_fLife = flag;
|
|
|
|
|
m_fLifePost = flag;
|
|
|
|
|
m_fLocalize = flag;
|
|
|
|
|
m_fMergeCond = flag;
|
|
|
|
|
m_fReloop = flag;
|
|
|
|
|
m_fReorder = flag;
|
|
|
|
|
m_fSplit = flag;
|
|
|
|
|
m_fSubst = flag;
|
|
|
|
|
m_fSubstConst = flag;
|
|
|
|
|
m_fTable = flag;
|
2006-08-26 13:35:28 +02:00
|
|
|
// And set specific optimization levels
|
|
|
|
|
if (level >= 3) {
|
2019-05-19 22:13:13 +02:00
|
|
|
m_inlineMult = -1; // Maximum inlining
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|