verilator/src/V3Error.h
2021-01-05 14:26:01 -05:00

419 lines
18 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Error handling
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2021 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 _V3ERROR_H_
#define _V3ERROR_H_ 1
#include "config_build.h"
#include "verilatedos.h"
// Limited V3 headers here - this is a base class for Vlc etc
#include "V3String.h"
#include <array>
#include <bitset>
#include <cassert>
#include <deque>
#include <map>
#include <set>
#include <sstream>
//######################################################################
class V3ErrorCode final {
public:
// clang-format off
enum en: uint8_t {
EC_MIN=0, // Keep first
//
EC_INFO, // General information out
EC_FATAL, // Kill the program
EC_FATALEXIT, // Kill the program, suppress with --quiet-exit
EC_FATALSRC, // Kill the program, for internal source errors
EC_ERROR, // General error out, can't suppress
// Boolean information we track per-line, but aren't errors
I_CELLDEFINE, // Inside cell define from `celldefine/`endcelldefine
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
I_LINT, // All lint messages
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
// Error codes:
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
E_ENCAPSULATED, // Error: local/protected violation
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
E_UNSUPPORTED, // Error: Unsupported (generally)
E_TASKNSVAR, // Error: Task I/O not simple
//
// Warning codes:
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
//
ALWCOMBORDER, // Always_comb with unordered statements
ASSIGNDLY, // Assignment delays
ASSIGNIN, // Assigning to input
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
BLKLOOPINIT, // Delayed assignment to array inside for loops
BLKSEQ, // Blocking assignments in sequential block
BSSPACE, // Backslash space
CASEINCOMPLETE, // Case statement has missing values
CASEOVERLAP, // Case statements overlap
CASEWITHX, // Case with X values
CASEX, // Casex
CASTCONST, // Cast is constant
CDCRSTLOGIC, // Logic in async reset path
CLKDATA, // Clock used as data
CMPCONST, // Comparison is constant due to limited range
COLONPLUS, // :+ instead of +:
COMBDLY, // Combinatorial delayed assignment
CONTASSREG, // Continuous assignment on reg
DEFPARAM, // Style: Defparam
DECLFILENAME, // Declaration doesn't match filename
DEPRECATED, // Feature will be deprecated
ENDLABEL, // End lable name mismatch
GENCLK, // Generated Clock
HIERBLOCK, // Ignored hierarchical block setting
IFDEPTH, // If statements too deep
IGNOREDRETURN, // Ignoring return value (function as task)
IMPERFECTSCH, // Imperfect schedule (disabled by default)
IMPLICIT, // Implicit wire
IMPORTSTAR, // Import::* in $unit
IMPURE, // Impure function not being inlined
INCABSPATH, // Include has absolute path
INFINITELOOP, // Infinite loop
INITIALDLY, // Initial delayed statement
INSECURE, // Insecure options
LATCH, // Latch detected outside of always_latch block
LITENDIAN, // Little bit endian vector
MODDUP, // Duplicate module
MULTIDRIVEN, // Driven from multiple blocks
MULTITOP, // Multiple top level modules
NOLATCH, // No latch detected in always_latch block
PINMISSING, // Cell pin not specified
PINNOCONNECT, // Cell pin not connected
PINCONNECTEMPTY,// Cell pin connected by name with empty reference
PKGNODECL, // Error: Package/class needs to be predeclared
PROCASSWIRE, // Procedural assignment on wire
RANDC, // Unsupported: 'randc' converted to 'rand'
REALCVT, // Real conversion
REDEFMACRO, // Redefining existing define macro
SELRANGE, // Selection index out of range
SHORTREAL, // Shortreal not supported
SPLITVAR, // Cannot split the variable
STMTDLY, // Delayed statement
SYMRSVDWORD, // Symbol is Reserved Word
SYNCASYNCNET, // Mixed sync + async reset
TICKCOUNT, // Too large tick count
TIMESCALEMOD, // Need timescale for module
UNDRIVEN, // No drivers
UNOPT, // Unoptimizable block
UNOPTFLAT, // Unoptimizable block after flattening
UNOPTTHREADS, // Thread partitioner unable to fill all requested threads
UNPACKED, // Unsupported unpacked
UNSIGNED, // Comparison is constant due to unsigned arithmetic
UNUSED, // No receivers
USERERROR, // Elaboration time $error
USERFATAL, // Elaboration time $fatal
USERINFO, // Elaboration time $info
USERWARN, // Elaboration time $warning
VARHIDDEN, // Hiding variable
WIDTH, // Width mismatch
WIDTHCONCAT, // Unsized numbers/parameters in concatenations
_ENUM_MAX
// ***Add new elements below also***
};
// clang-format on
enum en m_e;
inline V3ErrorCode()
: m_e{EC_MIN} {}
// cppcheck-suppress noExplicitConstructor
inline V3ErrorCode(en _e)
: m_e{_e} {}
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
explicit inline V3ErrorCode(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
const char* ascii() const {
// clang-format off
static const char* const names[] = {
// Leading spaces indicate it can't be disabled.
" MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR",
// Boolean
" I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
// Errors
"DETECTARRAY", "ENCAPSULATED", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR",
// Warnings
" EC_FIRST_WARN",
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
"CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG",
"DEFPARAM", "DECLFILENAME", "DEPRECATED",
"ENDLABEL", "GENCLK", "HIERBLOCK",
"IFDEPTH", "IGNOREDRETURN",
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
"LATCH", "LITENDIAN", "MODDUP",
"MULTIDRIVEN", "MULTITOP","NOLATCH",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PKGNODECL", "PROCASSWIRE",
"RANDC", "REALCVT", "REDEFMACRO",
"SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"TICKCOUNT", "TIMESCALEMOD",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
"UNPACKED", "UNSIGNED", "UNUSED",
"USERERROR", "USERFATAL", "USERINFO", "USERWARN",
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
" MAX"
};
// clang-format on
return names[m_e];
}
// Warnings that default to off
bool defaultsOff() const {
return (m_e == IMPERFECTSCH || m_e == I_CELLDEFINE || styleError());
}
// Warnings that warn about nasty side effects
bool dangerous() const { return (m_e == COMBDLY); }
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const {
return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG
|| m_e == IMPURE || m_e == PKGNODECL || m_e == PROCASSWIRE //
|| m_e == TIMESCALEMOD); // Says IEEE
}
// Warnings to mention manual
bool mentionManual() const {
return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || pretendError());
}
// Warnings that are lint only
bool lintError() const {
return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE
|| m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST
|| m_e == CMPCONST || m_e == COLONPLUS || m_e == ENDLABEL || m_e == IMPLICIT
|| m_e == LATCH || m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT
|| m_e == UNSIGNED || m_e == WIDTH);
}
// Warnings that are style only
bool styleError() const {
return (m_e == ASSIGNDLY // More than style, but for backward compatibility
|| m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == IMPORTSTAR
|| m_e == INCABSPATH || m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT
|| m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSED || m_e == VARHIDDEN);
}
};
inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) {
return lhs.m_e == rhs.m_e;
}
inline bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
return os << rhs.ascii();
}
//######################################################################
class V3Error final {
// Base class for any object that wants debugging and error reporting
typedef std::set<string> MessagesSet;
typedef void (*ErrorExitCb)(void);
private:
static bool s_describedWarnings; // Told user how to disable warns
static std::array<bool, V3ErrorCode::_ENUM_MAX>
s_describedEachWarn; // Told user specifics about this warning
static std::array<bool, V3ErrorCode::_ENUM_MAX>
s_pretendError; // Pretend this warning is an error
static int s_debugDefault; // Option: --debugi Default debugging level
static int s_errorLimit; // Option: --error-limit Number of errors before exit
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
static int s_errCount; // Error count
static int s_warnCount; // Warning count
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
static std::ostringstream s_errorStr; // Error string being formed
static V3ErrorCode s_errorCode; // Error string being formed will abort
static bool s_errorContexted; // Error being formed got context
static bool s_errorSuppressed; // Error being formed should be suppressed
static MessagesSet s_messages; // What errors we've outputted
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
static constexpr unsigned MAX_ERRORS = 50; // Fatal after this may errors
V3Error() {
std::cerr << ("Static class");
V3Error::vlAbort();
}
public:
// CONSTRUCTORS
// ACCESSORS
static void debugDefault(int level) { s_debugDefault = level; }
static int debugDefault() { return s_debugDefault; }
static void errorLimit(int level) { s_errorLimit = level; }
static int errorLimit() { return s_errorLimit; }
static void warnFatal(bool flag) { s_warnFatal = flag; }
static bool warnFatal() { return s_warnFatal; }
static string msgPrefix(); // returns %Error/%Warn
static int errorCount() { return s_errCount; }
static int warnCount() { return s_warnCount; }
static bool errorContexted() { return s_errorContexted; }
static void errorContexted(bool flag) { s_errorContexted = flag; }
// METHODS
static void incErrors();
static void incWarnings() { s_warnCount++; }
static void init();
static void abortIfErrors() {
if (errorCount()) abortIfWarnings();
}
static void abortIfWarnings();
static void suppressThisWarning(); // Suppress next %Warn if user has it off
static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code] = flag; }
static bool isError(V3ErrorCode code, bool supp);
static string lineStr(const char* filename, int lineno);
static V3ErrorCode errorCode() { return s_errorCode; }
static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; }
// When printing an error/warning, print prefix for multiline message
static string warnMore();
/// When building an error, don't show context info
static string warnContextNone() {
V3Error::errorContexted(true);
return "";
}
// Internals for v3error()/v3fatal() macros only
// Error end takes the string stream to output, be careful to seek() as needed
static void v3errorPrep(V3ErrorCode code) {
s_errorStr.str("");
s_errorCode = code;
s_errorContexted = false;
s_errorSuppressed = false;
}
static std::ostringstream& v3errorStr() { return s_errorStr; }
static void vlAbortOrExit();
static void vlAbort();
// static, but often overridden in classes.
static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = "");
};
// Global versions, so that if the class doesn't define a operator, we get the functions anyways.
inline int debug() { return V3Error::debugDefault(); }
inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
inline void v3errorEndFatal(std::ostringstream& sstr) {
V3Error::v3errorEnd(sstr);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE
}
// Theses allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
#define v3warnCode(code, msg) \
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
#define v3warnCodeFatal(code, msg) \
v3errorEndFatal( \
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()))
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
#define v3fatal(msg) v3warnCodeFatal(V3ErrorCode::EC_FATAL, msg)
// Use this instead of fatal() if message gets suppressed with --quiet-exit
#define v3fatalExit(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALEXIT, msg)
// Use this instead of fatal() to mention the source code line.
#define v3fatalSrc(msg) \
v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, \
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
// Use this when normal v3fatal is called in static method that overrides fileline.
#define v3fatalStatic(msg) \
(::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \
(V3Error::v3errorStr() << msg), V3Error::v3errorStr())))
#define UINFO(level, stmsg) \
do { \
if (VL_UNCOVERABLE(debug() >= (level))) { \
cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; \
} \
} while (false)
#define UINFONL(level, stmsg) \
do { \
if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } \
} while (false)
#ifdef VL_DEBUG
#define UDEBUGONLY(stmts) \
do { stmts } while (false)
#else
#define UDEBUGONLY(stmts) \
do { \
if (false) { stmts } \
} while (false)
#endif
// Assertion without object, generally UOBJASSERT preferred
#define UASSERT(condition, stmsg) \
do { \
if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); } \
} while (false)
// Assertion with object
#define UASSERT_OBJ(condition, obj, stmsg) \
do { \
if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); } \
} while (false)
// For use in V3Ast static functions only
#define UASSERT_STATIC(condition, stmsg) \
do { \
if (VL_UNCOVERABLE(!(condition))) { \
std::cerr << "Internal Error: " << __FILE__ << ":" << std::dec << __LINE__ << ":" \
<< (stmsg) << std::endl; \
V3Error::vlAbort(); \
} \
} while (false)
// Check self test values for expected value. Safe from side-effects.
// Type argument can be removed when go to C++11 (use auto).
#define UASSERT_SELFTEST(Type, got, exp) \
do { \
Type g = (got); \
Type e = (exp); \
UASSERT(g == e, "Self-test failed '" #got "==" #exp "'" \
" got=" \
<< g << " expected=" << e); \
} while (false)
#define V3ERROR_NA \
do { \
v3error("Internal: Unexpected Call"); \
v3fatalSrc("Unexpected Call"); \
} while (false)
/// Throw fatal and return a value. The return value will never really be
/// needed, but required to avoid compiler error.
#define V3ERROR_NA_RETURN(value) \
V3ERROR_NA; \
return value
/// Declare a convenience debug() routine that may be added to any class in
/// Verilator so that --debugi-<srcfile> will work to control UINFOs in
/// that class:
#define VL_DEBUG_FUNC \
static int debug() { \
static int level = -1; \
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); \
return level; \
}
//----------------------------------------------------------------------
#endif // Guard