// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Command line options
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************

#ifndef _V3OPTIONS_H_
#define _V3OPTIONS_H_ 1

#include "config_build.h"
#include "verilatedos.h"

#include "V3Global.h"
#include "V3LangCode.h"

#include <map>
#include <set>
#include <string>
#include <vector>

class V3OptionsImp;
class FileLine;

//######################################################################

class VOptionBool {
    // Class to track options that are either not specified (and default
    // true/false), versus user setting the option to true or false
public:
    enum en { OPT_DEFAULT_FALSE = 0, OPT_DEFAULT_TRUE, OPT_TRUE, OPT_FALSE, _ENUM_END };
    enum en m_e;
    inline VOptionBool()
        : m_e(OPT_DEFAULT_FALSE) {}
    // cppcheck-suppress noExplicitConstructor
    inline VOptionBool(en _e)
        : m_e(_e) {}
    explicit inline VOptionBool(int _e)
        : m_e(static_cast<en>(_e)) {}
    operator en() const { return m_e; }
    bool isDefault() const { return m_e == OPT_DEFAULT_FALSE || m_e == OPT_DEFAULT_TRUE; }
    bool isTrue() const { return m_e == OPT_TRUE || m_e == OPT_DEFAULT_TRUE; }
    bool isFalse() const { return m_e == OPT_FALSE || m_e == OPT_DEFAULT_FALSE; }
    bool isSetTrue() const { return m_e == OPT_TRUE; }
    bool isSetFalse() const { return m_e == OPT_FALSE; }
    void setTrueOrFalse(bool flag) { m_e = flag ? OPT_TRUE : OPT_FALSE; }
    const char* ascii() const {
        static const char* const names[] = {"DEFAULT_FALSE", "DEFAULT_TRUE", "TRUE", "FALSE"};
        return names[m_e];
    }
};
inline bool operator==(const VOptionBool& lhs, const VOptionBool& rhs) {
    return lhs.m_e == rhs.m_e;
}
inline bool operator==(const VOptionBool& lhs, VOptionBool::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VOptionBool::en lhs, const VOptionBool& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VOptionBool& rhs) {
    return os << rhs.ascii();
}

//######################################################################

class VTimescale {
public:
    enum en {
        // clang-format off
        TS_100S = 0, TS_10S = 1, TS_1S = 2,
        TS_100MS = 3, TS_10MS = 4, TS_1MS = 5,
        TS_100US = 6, TS_10US = 7, TS_1US = 8,
        TS_100NS = 9, TS_10NS = 10, TS_1NS = 11,
        TS_100PS = 12, TS_10PS = 13, TS_1PS = 14,
        TS_100FS = 15, TS_10FS = 16, TS_1FS = 17,
        // clang-format on
        NONE = 18,
        _ENUM_END
    };
    enum { TS_DEFAULT = TS_1PS };
    enum en m_e;
    // CONSTRUCTOR
    inline VTimescale()
        : m_e(NONE) {}
    // cppcheck-suppress noExplicitConstructor
    inline VTimescale(en _e)
        : m_e(_e) {}
    explicit inline VTimescale(int _e)
        : m_e(static_cast<en>(_e)) {}
    // Construct from string
    VTimescale(const string& value, bool& badr);
    VTimescale(double value, bool& badr) {
        badr = false;
        if (value == 10e2) {
            m_e = TS_100S;
        } else if (value == 1e1) {
            m_e = TS_10S;
        } else if (value == 1e0) {
            m_e = TS_1S;
        } else if (value == 1e-1) {
            m_e = TS_100MS;
        } else if (value == 1e-2) {
            m_e = TS_10MS;
        } else if (value == 1e-3) {
            m_e = TS_1MS;
        } else if (value == 1e-4) {
            m_e = TS_100US;
        } else if (value == 1e-5) {
            m_e = TS_10US;
        } else if (value == 1e-6) {
            m_e = TS_1US;
        } else if (value == 1e-7) {
            m_e = TS_100NS;
        } else if (value == 1e-8) {
            m_e = TS_10NS;
        } else if (value == 1e-9) {
            m_e = TS_1NS;
        } else if (value == 1e-10) {
            m_e = TS_100PS;
        } else if (value == 1e-11) {
            m_e = TS_10PS;
        } else if (value == 1e-12) {
            m_e = TS_1PS;
        } else if (value == 1e-13) {
            m_e = TS_100FS;
        } else if (value == 1e-14) {
            m_e = TS_10FS;
        } else if (value == 1e-15) {
            m_e = TS_1FS;
        } else {
            m_e = NONE;
            badr = true;
        }
    }
    bool isNone() const { return m_e == NONE; }
    // Parse a "unit/precision" string into two VTimescales, with error checking
    static void parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr, VTimescale& precr,
                             bool allowEmpty = false);
    const char* ascii() const {
        static const char* const names[]
            = {"100s", "10s", "1s",    "100ms", "10ms", "1ms",   "100us", "10us", "1us", "100ns",
               "10ns", "1ns", "100ps", "10ps",  "1ps",  "100fs", "10fs",  "1fs",  "NONE"};
        return names[m_e];
    }
    int powerOfTen() const { return 2 - static_cast<int>(m_e); }
    double multiplier() const {
        static const double values[]
            = {100,  10,   1,     1e-1,  1e-2,  1e-3,  1e-4,  1e-5,  1e-6, 1e-7,
               1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 0};
        return values[m_e];
    }
};
inline bool operator==(const VTimescale& lhs, const VTimescale& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VTimescale& lhs, VTimescale::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VTimescale::en lhs, const VTimescale& rhs) { return lhs == rhs.m_e; }
// Comparisons are based on time, not enum values, so seconds > milliseconds
inline bool operator<(const VTimescale& lhs, const VTimescale& rhs) { return lhs.m_e > rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VTimescale& rhs) {
    return os << rhs.ascii();
}

//######################################################################

class TraceFormat {
public:
    enum en { VCD = 0, FST } m_e;
    // cppcheck-suppress noExplicitConstructor
    inline TraceFormat(en _e = VCD)
        : m_e(_e) {}
    explicit inline TraceFormat(int _e)
        : m_e(static_cast<en>(_e)) {}
    operator en() const { return m_e; }
    bool fst() const { return m_e == FST; }
    string classBase() const {
        static const char* const names[] = {"VerilatedVcd", "VerilatedFst"};
        return names[m_e];
    }
    string sourceName() const {
        static const char* const names[] = {"verilated_vcd", "verilated_fst"};
        return names[m_e];
    }
};
inline bool operator==(const TraceFormat& lhs, const TraceFormat& rhs) {
    return lhs.m_e == rhs.m_e;
}
inline bool operator==(const TraceFormat& lhs, TraceFormat::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(TraceFormat::en lhs, const TraceFormat& rhs) { return lhs == rhs.m_e; }

typedef std::vector<string> V3StringList;
typedef std::set<string> V3StringSet;

//######################################################################
// V3Options - Command line options

class V3Options {
public:
private:
    // TYPES
    typedef std::map<string, int> DebugSrcMap;

    // MEMBERS (general options)
    V3OptionsImp* m_impp;  // Slow hidden options

    // clang-format off
    V3StringSet m_cppFiles;     // argument: C++ files to link against
    V3StringList m_cFlags;      // argument: user CFLAGS
    V3StringList m_ldLibs;      // argument: user LDFLAGS
    V3StringList m_makeFlags;   // argument: user MAKEFLAGS
    V3StringSet m_futures;      // argument: -Wfuture- list
    V3StringSet m_libraryFiles; // argument: Verilog -v files
    V3StringSet m_clockers;     // argument: Verilog -clk signals
    V3StringSet m_noClockers;   // argument: Verilog -noclk signals
    V3StringList m_vFiles;      // argument: Verilog files to read
    V3StringList m_forceIncs;   // argument: -FI
    DebugSrcMap m_debugSrcs;    // argument: --debugi-<srcfile>=<level>
    DebugSrcMap m_dumpTrees;    // argument: --dump-treei-<srcfile>=<level>
    std::map<string,string> m_parameters;  // Parameters

    bool        m_preprocOnly;  // main switch: -E
    bool        m_makePhony;    // main switch: -MP
    bool        m_preprocNoLine;// main switch: -P
    bool        m_assert;       // main switch: --assert
    bool        m_autoflush;    // main switch: --autoflush
    bool        m_bboxSys;      // main switch: --bbox-sys
    bool        m_bboxUnsup;    // main switch: --bbox-unsup
    bool        m_build;        // main switch: --build
    bool        m_cdc;          // main switch: --cdc
    bool        m_cmake;        // main switch: --make cmake
    bool        m_context;      // main switch: --Wcontext
    bool        m_coverageLine; // main switch: --coverage-block
    bool        m_coverageToggle;// main switch: --coverage-toggle
    bool        m_coverageUnderscore;// main switch: --coverage-underscore
    bool        m_coverageUser; // main switch: --coverage-func
    bool        m_debugCheck;   // main switch: --debug-check
    bool        m_debugCollision;  // main switch: --debug-collision
    bool        m_debugExitParse;  // main switch: --debug-exit-parse
    bool        m_debugLeak;    // main switch: --debug-leak
    bool        m_debugNondeterminism;  // main switch: --debug-nondeterminism
    bool        m_debugPartition;  // main switch: --debug-partition
    bool        m_debugProtect;  // main switch: --debug-protect
    bool        m_debugSelfTest;  // main switch: --debug-self-test
    bool        m_decoration;   // main switch: --decoration
    bool        m_dpiHdrOnly;   // main switch: --dpi-hdr-only
    bool        m_dumpDefines;  // main switch: --dump-defines
    bool        m_exe;          // main switch: --exe
    bool        m_flatten;      // main switch: --flatten
    bool        m_ignc;         // main switch: --ignc
    bool        m_inhibitSim;   // main switch: --inhibit-sim
    bool        m_lintOnly;     // main switch: --lint-only
    bool        m_gmake;        // main switch: --make gmake
    bool        m_main;         // main swithc: --main
    bool        m_orderClockDly;// main switch: --order-clock-delay
    bool        m_outFormatOk;  // main switch: --cc, --sc or --sp was specified
    bool        m_pedantic;     // main switch: --Wpedantic
    bool        m_pinsScUint;   // main switch: --pins-sc-uint
    bool        m_pinsScBigUint;// main switch: --pins-sc-biguint
    bool        m_pinsUint8;    // main switch: --pins-uint8
    bool        m_ppComments;   // main switch: --pp-comments
    bool        m_profCFuncs;   // main switch: --prof-cfuncs
    bool        m_profThreads;  // main switch: --prof-threads
    bool        m_protectIds;   // main switch: --protect-ids
    bool        m_public;       // main switch: --public
    bool        m_publicFlatRW;  // main switch: --public-flat-rw
    bool        m_quietExit;  // main switch: --quiet-exit
    bool        m_relativeCFuncs; // main switch: --relative-cfuncs
    bool        m_relativeIncludes; // main switch: --relative-includes
    bool        m_reportUnoptflat; // main switch: --report-unoptflat
    bool        m_savable;      // main switch: --savable
    bool        m_structsPacked;  // main switch: --structs-packed
    bool        m_systemC;      // main switch: --sc: System C instead of simple C++
    bool        m_stats;        // main switch: --stats
    bool        m_statsVars;    // main switch: --stats-vars
    bool        m_threadsCoarsen;  // main switch: --threads-coarsen
    bool        m_threadsDpiPure;  // main switch: --threads-dpi all/pure
    bool        m_threadsDpiUnpure;  // main switch: --threads-dpi all
    bool        m_trace;        // main switch: --trace
    bool        m_traceCoverage;  // main switch: --trace-coverage
    bool        m_traceParams;  // main switch: --trace-params
    bool        m_traceStructs; // main switch: --trace-structs
    bool        m_traceUnderscore;// main switch: --trace-underscore
    bool        m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
    bool        m_verilate;     // main swith: --verilate
    bool        m_vpi;          // main switch: --vpi
    bool        m_xInitialEdge; // main switch: --x-initial-edge
    bool        m_xmlOnly;      // main switch: --xml-only

    int         m_buildJobs;    // main switch: -j
    int         m_convergeLimit;// main switch: --converge-limit
    int         m_dumpTree;     // main switch: --dump-tree
    bool        m_dumpTreeAddrids;// main switch: --dump-tree-addrids
    int         m_gateStmts;    // main switch: --gate-stmts
    int         m_ifDepth;      // main switch: --if-depth
    int         m_inlineMult;   // main switch: --inline-mult
    VOptionBool m_makeDepend;  // main switch: -MMD
    int         m_maxNumWidth;  // main switch: --max-num-width
    int         m_moduleRecursion;// main switch: --module-recursion-depth
    int         m_outputSplit;  // main switch: --output-split
    int         m_outputSplitCFuncs;// main switch: --output-split-cfuncs
    int         m_outputSplitCTrace;// main switch: --output-split-ctrace
    int         m_pinsBv;       // main switch: --pins-bv
    VOptionBool m_skipIdentical;  // main switch: --skip-identical
    int         m_threads;      // main switch: --threads (0 == --no-threads)
    int         m_threadsMaxMTasks;  // main switch: --threads-max-mtasks
    VTimescale  m_timeDefaultPrec;  // main switch: --timescale
    VTimescale  m_timeDefaultUnit;  // main switch: --timescale
    VTimescale  m_timeOverridePrec;  // main switch: --timescale-override
    VTimescale  m_timeOverrideUnit;  // main switch: --timescale-override
    int         m_traceDepth;   // main switch: --trace-depth
    TraceFormat m_traceFormat;  // main switch: --trace or --trace-fst
    int         m_traceMaxArray;// main switch: --trace-max-array
    int         m_traceMaxWidth;// main switch: --trace-max-width
    int         m_traceThreads; // main switch: --trace-threads
    int         m_unrollCount;  // main switch: --unroll-count
    int         m_unrollStmts;  // main switch: --unroll-stmts

    int         m_compLimitBlocks;  // compiler selection; number of nested blocks
    int         m_compLimitMembers;  // compiler selection; number of members in struct before make anon array
    int         m_compLimitParens;  // compiler selection; number of nested parens

    string      m_bin;          // main switch: --bin {binary}
    string      m_exeName;      // main switch: -o {name}
    string      m_flags;        // main switch: -f {name}
    string      m_l2Name;       // main switch: --l2name; "" for top-module's name
    string      m_makeDir;      // main switch: -Mdir
    string      m_modPrefix;    // main switch: --mod-prefix
    string      m_pipeFilter;   // main switch: --pipe-filter
    string      m_prefix;       // main switch: --prefix
    string      m_protectKey;   // main switch: --protect-key
    string      m_protectLib;   // main switch: --protect-lib {lib_name}
    string      m_topModule;    // main switch: --top-module
    string      m_unusedRegexp; // main switch: --unused-regexp
    string      m_waiverOutput;  // main switch: --waiver-output {filename}
    string      m_xAssign;      // main switch: --x-assign
    string      m_xInitial;     // main switch: --x-initial
    string      m_xmlOutput;    // main switch: --xml-output

    // Language is now held in FileLine, on a per-node basis. However we still
    // have a concept of the default language at a global level.
    V3LangCode  m_defaultLanguage;      // main switch: --language

    // MEMBERS (optimizations)
    //                          // main switch: -Op: --public
    bool        m_oAcycSimp;    // main switch: -Oy: acyclic pre-optimizations
    bool        m_oAssemble;    // main switch: -Om: assign assemble
    bool        m_oCase;        // main switch: -Oe: case tree conversion
    bool        m_oCombine;     // main switch: -Ob: common icode packing
    bool        m_oConst;       // main switch: -Oc: constant folding
    bool        m_oDedupe;      // main switch: -Od: logic deduplication
    bool        m_oExpand;      // main switch: -Ox: expansion of C macros
    bool        m_oGate;        // main switch: -Og: gate wire elimination
    bool        m_oInline;      // main switch: -Oi: module inlining
    bool        m_oLife;        // main switch: -Ol: variable lifetime
    bool        m_oLifePost;    // main switch: -Ot: delayed assignment elimination
    bool        m_oLocalize;    // main switch: -Oz: convert temps to local variables
    bool        m_oMergeCond;   // main switch: -Ob: merge conditionals
    bool        m_oReloop;      // main switch: -Ov: reform loops
    bool        m_oReorder;     // main switch: -Or: reorder assignments in blocks
    bool        m_oSplit;       // main switch: -Os: always assignment splitting
    bool        m_oSubst;       // main switch: -Ou: substitute expression temp values
    bool        m_oSubstConst;  // main switch: -Ok: final constant substitution
    bool        m_oTable;       // main switch: -Oa: lookup table creation
    // clang-format on

private:
    // METHODS
    void addArg(const string& arg);
    void addDefine(const string& defline, bool allowPlus);
    void addFuture(const string& flag);
    void addIncDirUser(const string& incdir);  // User requested
    void addIncDirFallback(const string& incdir);  // Low priority if not found otherwise
    void addParameter(const string& paramline, bool allowPlus);
    void addLangExt(const string& langext, const V3LangCode& lc);
    void addLibExtV(const string& libext);
    void optimize(int level);
    void showVersion(bool verbose);
    void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; }
    bool onoff(const char* sw, const char* arg, bool& flag);
    bool onoffb(const char* sw, const char* arg, VOptionBool& flagr);
    bool suffixed(const string& sw, const char* arg);
    string parseFileArg(const string& optdir, const string& relfilename);
    bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc);
    string filePathCheckOneDir(const string& modname, const string& dirname);

    // CONSTRUCTORS
    VL_UNCOPYABLE(V3Options);

public:
    V3Options();
    ~V3Options();
    void setDebugMode(int level);
    void setDebugSrcLevel(const string& srcfile, int level);
    int debugSrcLevel(const string& srcfile_path, int default_level = V3Error::debugDefault());
    void setDumpTreeLevel(const string& srcfile, int level);
    int dumpTreeLevel(const string& srcfile_path);

    // METHODS
    void addCppFile(const string& filename);
    void addCFlags(const string& filename);
    void addLdLibs(const string& filename);
    void addMakeFlags(const string& filename);
    void addLibraryFile(const string& filename);
    void addClocker(const string& signame);
    void addNoClocker(const string& signame);
    void addVFile(const string& filename);
    void addForceInc(const string& filename);
    void notify();

    // ACCESSORS (options)
    bool preprocOnly() const { return m_preprocOnly; }
    bool makePhony() const { return m_makePhony; }
    bool preprocNoLine() const { return m_preprocNoLine; }
    bool underlineZero() const { return m_underlineZero; }
    string bin() const { return m_bin; }
    string flags() const { return m_flags; }
    bool systemC() const { return m_systemC; }
    bool usingSystemCLibs() const { return !lintOnly() && systemC(); }
    bool savable() const { return m_savable; }
    bool stats() const { return m_stats; }
    bool statsVars() const { return m_statsVars; }
    bool structsPacked() const { return m_structsPacked; }
    bool assertOn() const { return m_assert; }  // assertOn as __FILE__ may be defined
    bool autoflush() const { return m_autoflush; }
    bool bboxSys() const { return m_bboxSys; }
    bool bboxUnsup() const { return m_bboxUnsup; }
    bool build() const { return m_build; }
    bool cdc() const { return m_cdc; }
    bool cmake() const { return m_cmake; }
    bool context() const { return m_context; }
    bool coverage() const { return m_coverageLine || m_coverageToggle || m_coverageUser; }
    bool coverageLine() const { return m_coverageLine; }
    bool coverageToggle() const { return m_coverageToggle; }
    bool coverageUnderscore() const { return m_coverageUnderscore; }
    bool coverageUser() const { return m_coverageUser; }
    bool debugCheck() const { return m_debugCheck; }
    bool debugCollision() const { return m_debugCollision; }
    bool debugExitParse() const { return m_debugExitParse; }
    bool debugLeak() const { return m_debugLeak; }
    bool debugNondeterminism() const { return m_debugNondeterminism; }
    bool debugPartition() const { return m_debugPartition; }
    bool debugProtect() const { return m_debugProtect; }
    bool debugSelfTest() const { return m_debugSelfTest; }
    bool decoration() const { return m_decoration; }
    bool dpiHdrOnly() const { return m_dpiHdrOnly; }
    bool dumpDefines() const { return m_dumpDefines; }
    bool exe() const { return m_exe; }
    bool flatten() const { return m_flatten; }
    bool gmake() const { return m_gmake; }
    bool threadsDpiPure() const { return m_threadsDpiPure; }
    bool threadsDpiUnpure() const { return m_threadsDpiUnpure; }
    bool threadsCoarsen() const { return m_threadsCoarsen; }
    bool trace() const { return m_trace; }
    bool traceCoverage() const { return m_traceCoverage; }
    bool traceParams() const { return m_traceParams; }
    bool traceStructs() const { return m_traceStructs; }
    bool traceUnderscore() const { return m_traceUnderscore; }
    bool main() const { return m_main; }
    bool orderClockDly() const { return m_orderClockDly; }
    bool outFormatOk() const { return m_outFormatOk; }
    bool keepTempFiles() const { return (V3Error::debugDefault() != 0); }
    bool pedantic() const { return m_pedantic; }
    bool pinsScUint() const { return m_pinsScUint; }
    bool pinsScBigUint() const { return m_pinsScBigUint; }
    bool pinsUint8() const { return m_pinsUint8; }
    bool ppComments() const { return m_ppComments; }
    bool profCFuncs() const { return m_profCFuncs; }
    bool profThreads() const { return m_profThreads; }
    bool protectIds() const { return m_protectIds; }
    bool allPublic() const { return m_public; }
    bool publicFlatRW() const { return m_publicFlatRW; }
    bool lintOnly() const { return m_lintOnly; }
    bool ignc() const { return m_ignc; }
    bool inhibitSim() const { return m_inhibitSim; }
    bool quietExit() const { return m_quietExit; }
    bool relativeCFuncs() const { return m_relativeCFuncs; }
    bool reportUnoptflat() const { return m_reportUnoptflat; }
    bool verilate() const { return m_verilate; }
    bool vpi() const { return m_vpi; }
    bool xInitialEdge() const { return m_xInitialEdge; }
    bool xmlOnly() const { return m_xmlOnly; }

    int buildJobs() const { return m_buildJobs; }
    int convergeLimit() const { return m_convergeLimit; }
    int dumpTree() const { return m_dumpTree; }
    bool dumpTreeAddrids() const { return m_dumpTreeAddrids; }
    int gateStmts() const { return m_gateStmts; }
    int ifDepth() const { return m_ifDepth; }
    int inlineMult() const { return m_inlineMult; }
    VOptionBool makeDepend() const { return m_makeDepend; }
    int maxNumWidth() const { return m_maxNumWidth; }
    int moduleRecursionDepth() const { return m_moduleRecursion; }
    int outputSplit() const { return m_outputSplit; }
    int outputSplitCFuncs() const { return m_outputSplitCFuncs; }
    int outputSplitCTrace() const { return m_outputSplitCTrace; }
    int pinsBv() const { return m_pinsBv; }
    VOptionBool skipIdentical() const { return m_skipIdentical; }
    int threads() const { return m_threads; }
    int threadsMaxMTasks() const { return m_threadsMaxMTasks; }
    bool mtasks() const { return (m_threads > 1); }
    VTimescale timeDefaultPrec() const { return m_timeDefaultPrec; }
    VTimescale timeDefaultUnit() const { return m_timeDefaultUnit; }
    VTimescale timeOverridePrec() const { return m_timeOverridePrec; }
    VTimescale timeOverrideUnit() const { return m_timeOverrideUnit; }
    VTimescale timeComputePrec(const VTimescale& flag) const;
    VTimescale timeComputeUnit(const VTimescale& flag) const;
    int traceDepth() const { return m_traceDepth; }
    TraceFormat traceFormat() const { return m_traceFormat; }
    int traceMaxArray() const { return m_traceMaxArray; }
    int traceMaxWidth() const { return m_traceMaxWidth; }
    int traceThreads() const { return m_traceThreads; }
    bool trueTraceThreads() const {
        return traceThreads() == 0 ? 0 : traceThreads() - traceFormat().fst();
    }
    int unrollCount() const { return m_unrollCount; }
    int unrollStmts() const { return m_unrollStmts; }

    int compLimitBlocks() const { return m_compLimitBlocks; }
    int compLimitMembers() const { return m_compLimitMembers; }
    int compLimitParens() const { return m_compLimitParens; }

    string exeName() const { return m_exeName != "" ? m_exeName : prefix(); }
    string l2Name() const { return m_l2Name; }
    string makeDir() const { return m_makeDir; }
    string modPrefix() const { return m_modPrefix; }
    string pipeFilter() const { return m_pipeFilter; }
    string prefix() const { return m_prefix; }
    string protectKey() const { return m_protectKey; }
    string protectKeyDefaulted();  // Set default key if not set by user
    string protectLib() const { return m_protectLib; }
    string protectLibName(bool shared) {
        string libName = "lib" + protectLib();
        if (shared) {
            libName += ".so";
        } else {
            libName += ".a";
        }
        return libName;
    }
    string topModule() const { return m_topModule; }
    string unusedRegexp() const { return m_unusedRegexp; }
    string waiverOutput() const { return m_waiverOutput; }
    bool isWaiverOutput() const { return !m_waiverOutput.empty(); }
    string xAssign() const { return m_xAssign; }
    string xInitial() const { return m_xInitial; }
    string xmlOutput() const { return m_xmlOutput; }

    const V3StringSet& cppFiles() const { return m_cppFiles; }
    const V3StringList& cFlags() const { return m_cFlags; }
    const V3StringList& ldLibs() const { return m_ldLibs; }
    const V3StringList& makeFlags() const { return m_makeFlags; }
    const V3StringSet& libraryFiles() const { return m_libraryFiles; }
    const V3StringList& vFiles() const { return m_vFiles; }
    const V3StringList& forceIncs() const { return m_forceIncs; }
    const V3LangCode& defaultLanguage() const { return m_defaultLanguage; }

    bool hasParameter(const string& name);
    string parameter(const string& name);
    void checkParameters();

    bool isFuture(const string& flag) const;
    bool isLibraryFile(const string& filename) const;
    bool isClocker(const string& signame) const;
    bool isNoClocker(const string& signame) const;

    // ACCESSORS (optimization options)
    bool oAcycSimp() const { return m_oAcycSimp; }
    bool oAssemble() const { return m_oAssemble; }
    bool oCase() const { return m_oCase; }
    bool oCombine() const { return m_oCombine; }
    bool oConst() const { return m_oConst; }
    bool oDedupe() const { return m_oDedupe; }
    bool oExpand() const { return m_oExpand; }
    bool oGate() const { return m_oGate; }
    bool oInline() const { return m_oInline; }
    bool oLife() const { return m_oLife; }
    bool oLifePost() const { return m_oLifePost; }
    bool oLocalize() const { return m_oLocalize; }
    bool oMergeCond() const { return m_oMergeCond; }
    bool oReloop() const { return m_oReloop; }
    bool oReorder() const { return m_oReorder; }
    bool oSplit() const { return m_oSplit; }
    bool oSubst() const { return m_oSubst; }
    bool oSubstConst() const { return m_oSubstConst; }
    bool oTable() const { return m_oTable; }

    string traceClassBase() const { return m_traceFormat.classBase(); }
    string traceClassLang() const { return m_traceFormat.classBase() + (systemC() ? "Sc" : "C"); }
    string traceSourceBase() const { return m_traceFormat.sourceName(); }
    string traceSourceLang() const {
        return m_traceFormat.sourceName() + (systemC() ? "_sc" : "_c");
    }

    // METHODS (from main)
    static string version();
    static string argString(int argc, char** argv);  ///< Return list of arguments as simple string
    string allArgsString() const;  ///< Return all passed arguments as simple string
    void bin(const string& flag) { m_bin = flag; }
    void parseOpts(FileLine* fl, int argc, char** argv);
    void parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv);
    void parseOptsFile(FileLine* fl, const string& filename, bool rel);

    // METHODS (environment)
    // Most of these may be built into the executable with --enable-defenv,
    // see the README.  If adding new variables, also see src/Makefile_obj.in
    // Also add to V3Options::showVersion()
    static string getenvBuiltins(const string& var);
    static string getenvMAKE();
    static string getenvPERL();
    static string getenvSYSTEMC();
    static string getenvSYSTEMC_ARCH();
    static string getenvSYSTEMC_INCLUDE();
    static string getenvSYSTEMC_LIBDIR();
    static string getenvVERILATOR_ROOT();
    static bool systemCSystemWide();
    static bool systemCFound();  // SystemC installed, or environment points to it

    // METHODS (file utilities using these options)
    string fileExists(const string& filename);
    string filePath(FileLine* fl, const string& modname, const string& lastpath,
                    const string& errmsg);
    void filePathLookedMsg(FileLine* fl, const string& modname);
    V3LangCode fileLanguage(const string& filename);
    static bool fileStatDir(const string& filename);
    static bool fileStatNormal(const string& filename);
    static void fileNfsFlush(const string& filename);

    // METHODS (other OS)
    static void throwSigsegv();
};

//######################################################################

#endif  // guard
