Add simplistic class support with many restrictions, see manual, #377.

This commit is contained in:
Wilson Snyder 2020-04-05 09:30:23 -04:00
parent f6048cc9c1
commit 6eadb8e771
101 changed files with 2258 additions and 66 deletions

View File

@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.033 devel
** Add simplistic class support with many restrictions, see manual, #377.
* Verilator 4.032 2020-04-04

View File

@ -3558,6 +3558,13 @@ ___05F (5F is the hex code of an underscore.)
Verilator only supports "bind" to a target module name, not an instance
path.
=head2 Class
Verilator class support is very limited and in active development.
Verilator supports members, and methods. Verilator doe not support initial
values on class members, class static members, class new methods, class
extend, or class parameters.
=head2 Dotted cross-hierarchy references
Verilator supports dotted references to variables, functions and tasks in

View File

@ -2088,12 +2088,19 @@ const char* Verilated::commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
return outstr;
}
void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE {
// Slowpath - Called only on error
VL_FATAL_MT(filename, linenum, "", "Null pointer dereferenced");
VL_UNREACHABLE
}
void Verilated::overWidthError(const char* signame) VL_MT_SAFE {
// Slowpath - Called only when signal sets too high of a bit
std::string msg = (std::string("Testbench C set input '")
+ signame
+ "' to value that overflows what the signal's width can fit");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
VL_UNREACHABLE
}
void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE {

View File

@ -510,7 +510,8 @@ public:
const char* delimiter = "."); // Returns static data
// Internal: Throw signal assertion
static void overWidthError(const char* signame) VL_MT_SAFE;
static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE;
static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE;
// Internal: Find scope
static const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE;

View File

@ -28,6 +28,7 @@
#include <deque>
#include <map>
#include <memory>
#include <string>
//===================================================================
@ -370,6 +371,24 @@ template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
return obj.to_string();
}
//===================================================================
// Verilog class reference container
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || (__cplusplus >= 201103L)
# define VlClassRef std::shared_ptr
#else
# define VlClassRef VlClassRef__SystemVerilog_class_support_requires_a_C11_or_newer_compiler
#endif
template <class T> // T typically of type VlClassRef<x>
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
return t;
}
//======================================================================
// Conversion functions

View File

@ -167,6 +167,7 @@ RAW_OBJS = \
V3Cast.o \
V3Cdc.o \
V3Changed.o \
V3Class.o \
V3Clean.o \
V3Clock.o \
V3Combine.o \

View File

@ -2289,21 +2289,23 @@ private:
uint64_t m_dpiOpenParent; // DPI import open array, if !=0, how many callees
bool m_taskPublic:1; // Public task
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
bool m_classMethod:1; // Class method
bool m_prototype:1; // Just a prototype
bool m_dpiExport:1; // DPI exported
bool m_dpiImport:1; // DPI imported
bool m_dpiContext:1; // DPI import context
bool m_dpiOpenChild:1; // DPI import open array child wrapper
bool m_dpiTask:1; // DPI import task (vs. void function)
bool m_pure:1; // DPI import pure
bool m_isConstructor:1; // Class constructor
bool m_pure:1; // DPI import pure (vs. virtual pure)
public:
AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
: AstNode(t, fl)
, m_name(name)
, m_dpiOpenParent(0), m_taskPublic(false)
, m_attrIsolateAssign(false), m_prototype(false)
, m_attrIsolateAssign(false), m_classMethod(false), m_prototype(false)
, m_dpiExport(false), m_dpiImport(false), m_dpiContext(false)
, m_dpiOpenChild(false), m_dpiTask(false), m_pure(false) {
, m_dpiOpenChild(false), m_dpiTask(false), m_isConstructor(false), m_pure(false) {
addNOp3p(stmtsp);
cname(name); // Might be overridden by dpi import/export
}
@ -2334,6 +2336,8 @@ public:
bool taskPublic() const { return m_taskPublic; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
void classMethod(bool flag) { m_classMethod = flag; }
bool classMethod() const { return m_classMethod; }
void prototype(bool flag) { m_prototype = flag; }
bool prototype() const { return m_prototype; }
void dpiExport(bool flag) { m_dpiExport = flag; }
@ -2346,6 +2350,8 @@ public:
bool dpiOpenChild() const { return m_dpiOpenChild; }
void dpiTask(bool flag) { m_dpiTask = flag; }
bool dpiTask() const { return m_dpiTask; }
void isConstructor(bool flag) { m_isConstructor = flag; }
bool isConstructor() const { return m_isConstructor; }
void pure(bool flag) { m_pure = flag; }
bool pure() const { return m_pure; }
};

View File

@ -328,6 +328,10 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT
out += "> ";
info.m_oprefix = out;
return info;
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
VlArgTypeRecursed info;
info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
return info;
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed);
info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix;
@ -999,6 +1003,43 @@ void AstCellInline::dump(std::ostream& str) const {
this->AstNode::dump(str);
str<<" -> "<<origModName();
}
const char* AstClassPackage::broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
BROKEN_RTN(m_classp && !m_classp->brokeExists());
return NULL;
}
void AstClass::insertCache(AstNode* nodep) {
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeFTask) || VN_IS(nodep, EnumItemRef)) {
if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
} else {
m_members.insert(make_pair(nodep->name(), nodep));
}
}
}
void AstClass::repairCache() {
clearCache();
for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) {
insertCache(itemp);
}
}
void AstClass::dump(std::ostream& str) const {
this->AstNode::dump(str);
}
AstClass* AstClassExtends::classp() const {
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
UASSERT_OBJ(refp, this, "class extends non-ref");
return refp->classp();
}
void AstClassRefDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (classp()) { str<<" -> "; classp()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstClassRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str<<"class:"<<name();
}
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (immediate()) str<<" [IMMEDIATE]";
@ -1276,6 +1317,7 @@ void AstVar::dump(std::ostream& str) const {
if (attrClockEn()) str<<" [aCLKEN]";
if (attrIsolateAssign()) str<<" [aISO]";
if (attrFileDescr()) str<<" [aFD]";
if (isClassMember()) str<<" [MEMBER]";
if (isFuncReturn()) str<<" [FUNCRTN]";
else if (isFuncLocal()) str<<" [FUNC]";
if (isDpiOpenArray()) str<<" [DPIOPENA]";
@ -1320,6 +1362,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
}
void AstNodeFTask::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (classMethod()) str<<" [METHOD]";
if (taskPublic()) str<<" [PUBLIC]";
if (prototype()) str<<" [PROTOTYPE]";
if (dpiImport()) str<<" [DPII]";

View File

@ -247,20 +247,75 @@ public:
AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Range of pin
};
class AstClass : public AstNode {
//######################################################################
// Classes
class AstClassPackage : public AstNodeModule {
// The static information portion of a class (treated similarly to a package)
AstClass* m_classp; // Class package this is under (weak pointer, hard link is other way)
public:
AstClassPackage(FileLine* fl, const string& name)
: ASTGEN_SUPER(fl, name) {}
ASTNODE_NODE_FUNCS(ClassPackage)
virtual string verilogKwd() const { return "/*class*/package"; }
virtual const char* broken() const;
AstClass* classp() const { return m_classp; }
void classp(AstClass* classp) { m_classp = classp; }
};
class AstClass : public AstNodeModule {
// TYPES
typedef std::map<string, AstNode*> MemberNameMap;
// MEMBERS
string m_name; // Name
MemberNameMap m_members; // Members or method children
AstClassPackage* m_packagep; // Class package this is under
void insertCache(AstNode* nodep);
public:
AstClass(FileLine* fl, const string& name)
: ASTGEN_SUPER(fl)
, m_name(name) {}
: ASTGEN_SUPER(fl, name)
, m_packagep(NULL) {}
ASTNODE_NODE_FUNCS(Class)
virtual string name() const { return m_name; } // * = Var name
virtual void name(const string& name) { m_name = name; }
virtual string verilogKwd() const { return "class"; }
virtual bool maybePointedTo() const { return true; }
AstNode* membersp() const { return op1p(); } // op1 = List of statements
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
virtual void dump(std::ostream& str) const;
virtual const char* broken() const {
BROKEN_BASE_RTN(AstNodeModule::broken());
BROKEN_RTN(m_packagep && !m_packagep->brokeExists());
return NULL;
}
// op1/op2/op3 in AstNodeModule
AstClassPackage* packagep() const { return m_packagep; }
void packagep(AstClassPackage* classpackagep) { m_packagep = classpackagep; }
AstNode* membersp() const { return stmtsp(); } // op2 = List of statements
void addMembersp(AstNode* nodep) {
insertCache(nodep);
addStmtp(nodep);
}
AstClassExtends* extendsp() const { return VN_CAST(op4p(), ClassExtends); }
void extendsp(AstNode* nodep) { addNOp2p(nodep); }
void clearCache() { m_members.clear(); }
void repairCache();
AstNode* findMember(const string& name) const {
MemberNameMap::const_iterator it = m_members.find(name);
return (it == m_members.end()) ? NULL : it->second;
}
};
class AstClassExtends : public AstNode {
// Children: AstClassRefDType during early parse, then moves to dtype
public:
AstClassExtends(FileLine* fl, AstNodeDType* dtp)
: ASTGEN_SUPER(fl) {
childDTypep(dtp); // Only for parser
}
ASTNODE_NODE_FUNCS(ClassExtends)
virtual string verilogKwd() const { return "extends"; }
virtual bool hasDType() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Type assigning to
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstClass* classp() const; // Class being extended (after link)
};
//######################################################################
@ -778,8 +833,11 @@ public:
const AstClassRefDType* asamep = static_cast<const AstClassRefDType*>(samep);
return (m_classp == asamep->m_classp
&& m_packagep == asamep->m_packagep); }
virtual bool similarDType(AstNodeDType* samep) const { return this == samep; }
virtual bool similarDType(AstNodeDType* samep) const {
return this == samep || same(samep); }
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_classp), V3Hash(m_packagep)); }
virtual void dump(std::ostream& str=std::cout) const;
virtual void dumpSmall(std::ostream& str) const;
virtual string name() const { return classp() ? classp()->name() : "<unlinked>"; }
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
@ -1498,6 +1556,7 @@ private:
bool m_usedClock:1; // Signal used as a clock
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
bool m_usedLoopIdx:1; // Variable subject of for unrolling
bool m_classMember:1; // Member variable for a class
bool m_funcLocal:1; // Local variable for a function
bool m_funcReturn:1; // Return variable for a function
bool m_attrClockEn:1;// User clock enable attribute
@ -1525,6 +1584,7 @@ private:
m_usedClock = false; m_usedParam = false; m_usedLoopIdx = false;
m_sigPublic = false; m_sigModPublic = false;
m_sigUserRdPublic = false; m_sigUserRWPublic = false;
m_classMember = false;
m_funcLocal = false; m_funcReturn = false;
m_attrClockEn = false; m_attrScBv = false;
m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false;
@ -1645,6 +1705,7 @@ public:
void isConst(bool flag) { m_isConst = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void classMember(bool flag) { m_classMember = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; }
void funcReturn(bool flag) { m_funcReturn = flag; }
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
@ -1699,6 +1760,7 @@ public:
bool isTrace() const { return m_trace; }
bool isConst() const { return m_isConst; }
bool isStatic() const { return m_isStatic; }
bool isClassMember() const { return m_classMember; }
bool isFuncLocal() const { return m_funcLocal; }
bool isFuncReturn() const { return m_funcReturn; }
bool isPullup() const { return m_isPullup; }
@ -4099,6 +4161,27 @@ public:
return fileline() == samep->fileline(); }
};
class AstNullCheck : public AstNodeUniop {
// Return LHS after checking that LHS is non-null
// Children: VarRef or something returning pointer
public:
AstNullCheck(FileLine* fl, AstNode* lhsp)
: ASTGEN_SUPER(fl, lhsp) {
dtypeFrom(lhsp);
}
ASTNODE_NODE_FUNCS(NullCheck)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual int instrCount() const { return 1; } // Rarely executes
virtual string emitVerilog() { return "%l"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual V3Hash sameHash() const { return V3Hash(fileline()->lineno()); }
virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); }
};
class AstTraceDecl : public AstNodeStmt {
// Trace point declaration
// Separate from AstTraceInc; as a declaration can't be deleted

View File

@ -49,6 +49,7 @@ private:
int m_funcNum; // Function number being built
public:
AstCFunc* builtFuncp() const { return m_tlFuncp; }
void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs()
&& v3Global.opt.outputSplitCFuncs() < m_numStmts) {
@ -59,7 +60,7 @@ public:
m_basename+"_"+cvtToStr(++m_funcNum), NULL, "void");
m_funcp->isStatic(false);
m_funcp->declPrivate(true);
m_funcp->slow(true);
m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
m_funcp->argTypes(m_argsp);
m_modp->addStmtp(m_funcp);
@ -86,7 +87,7 @@ public:
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void");
m_tlFuncp->declPrivate(true);
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(true);
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
m_tlFuncp->argTypes(m_argsp);
if (stmt != "") {
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
@ -146,8 +147,10 @@ void V3CCtors::cctorsAll() {
for (AstNodeModule* modp = v3Global.rootp()->modulesp();
modp; modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn
AstCFunc* varResetFuncp;
{
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
varResetFuncp = var_reset.builtFuncp();
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) {
if (!varp->isIfaceParent() && !varp->isIfaceRef()
@ -172,5 +175,20 @@ void V3CCtors::cctorsAll() {
}
}
}
if (VN_IS(modp, Class)) {
AstCFunc* funcp = new AstCFunc(modp->fileline(), "new", NULL, "");
funcp->isConstructor(true);
funcp->isStatic(false);
funcp->slow(false);
modp->addStmtp(funcp);
funcp->addStmtsp(new AstCCall(varResetFuncp->fileline(), varResetFuncp));
}
if (VN_IS(modp, Class)) {
AstCFunc* funcp = new AstCFunc(modp->fileline(), "~", NULL, "");
funcp->isDestructor(true);
funcp->isStatic(false);
funcp->slow(false);
modp->addStmtp(funcp);
}
}
}

View File

@ -18,6 +18,9 @@
// Each module:
// Each cell:
// Create CUse for cell forward declaration
// Each class:
// Create string access functions
// Search for dtypes referencing class, and create CUse for forward declaraion
//
//*************************************************************************
@ -44,6 +47,8 @@ private:
// Entire netlist:
// AstClass::user1() -> bool. True if class needs to_string dumper
AstUser1InUse m_inuser1;
// AstClass::user2() -> bool. True if iterated
AstUser2InUse m_inuser2;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -67,6 +72,49 @@ public:
VL_UNCOPYABLE(CUseState);
};
// Visit within a module all nodes and data types they reference, finding
// any classes so we can make sure they are defined when Verilated code
// compiles
class CUseDTypeVisitor : public AstNVisitor {
// MEMBERS
CUseState& m_stater; // State for inserter
bool m_impOnly; // In details needed only for implementation
// METHODS
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
if (nodep->user2SetOnce()) return; // Process once
if (!m_impOnly) m_stater.newUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name());
// No class.h, it's inside the class package's h file
m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->packagep()->name());
// Need to include extends() when we implement, but no need for pointers to know
bool oldImpOnly = m_impOnly;
{
m_impOnly = true;
iterateChildren(nodep->classp()); // This also gets all extend classes
}
m_impOnly = oldImpOnly;
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
if (nodep->user2SetOnce()) return; // Process once
if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep());
if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p());
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
if (nodep->user2SetOnce()) return; // Process once
if (nodep->dtypep() && !nodep->dtypep()->user2()) iterate(nodep->dtypep());
iterateChildren(nodep);
}
public:
// CONSTRUCTORS
explicit CUseDTypeVisitor(AstNodeModule* nodep, CUseState& stater)
: m_stater(stater)
, m_impOnly(false) {
iterate(nodep);
}
virtual ~CUseDTypeVisitor() {}
VL_UNCOPYABLE(CUseDTypeVisitor);
};
class CUseVisitor : public AstNVisitor {
// MEMBERS
CUseState m_state; // Inserter state
@ -83,6 +131,62 @@ class CUseVisitor : public AstNVisitor {
}
}
}
void makeVlToString(AstClass* nodep) {
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "VL_TO_STRING", NULL, "std::string");
funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep)
+ ">& obj");
funcp->isMethod(false);
funcp->isConst(false);
funcp->isStatic(false);
funcp->protect(false);
AstNode* exprp = new AstCMath(nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0);
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp));
nodep->addStmtp(funcp);
}
void makeToString(AstClass* nodep) {
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string", NULL, "std::string");
funcp->isConst(true);
funcp->isStatic(false);
funcp->protect(false);
AstNode* exprp = new AstCMath(nodep->fileline(),
"std::string(\"`{\") + to_string_middle() + \"}\"", 0);
exprp->dtypeSetString();
funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp));
nodep->addStmtp(funcp);
}
void makeToStringMiddle(AstClass* nodep) {
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "to_string_middle", NULL, "std::string");
funcp->isConst(true);
funcp->isStatic(false);
funcp->protect(false);
funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n"));
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var)) {
string stmt = "out += \"";
stmt += comma;
comma = ", ";
stmt += itemp->origNameProtect();
stmt += ":\" + VL_TO_STRING(";
stmt += itemp->nameProtect();
stmt += ");\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
}
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {
string stmt = "out += \"";
if (!comma.empty()) stmt += "\", \"+ ";
comma = ", ";
stmt += nodep->extendsp()->dtypep()->nameProtect();
stmt += "::to_string_middle();\n";
nodep->user1(true); // So what we extend dumps this
funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
funcp->addStmtsp(new AstCStmt(nodep->fileline(), "return out;\n"));
nodep->addStmtp(funcp);
}
// VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@ -92,6 +196,12 @@ class CUseVisitor : public AstNVisitor {
usep->protect(false);
}
makeUseCells(nodep);
{ CUseDTypeVisitor dtypeVisitor(nodep, m_state); }
if (AstClass* classp = VN_CAST(nodep, Class)) {
makeVlToString(classp);
makeToString(classp);
makeToStringMiddle(classp);
}
}
virtual void visit(AstNode*) VL_OVERRIDE {} // All in AstNodeModule

View File

@ -96,6 +96,15 @@ private:
insertCast(nodep->lhsp(), VL_IDATASIZE);
}
}
void ensureNullChecked(AstNode* nodep) {
// TODO optimize to track null checked values and avoid where possible
if (!VN_IS(nodep->backp(), NullCheck)) {
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
AstNode* newp = new AstNullCheck(nodep->fileline(), nodep);
relinkHandle.relink(newp);
}
}
// VISITORS
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
@ -156,6 +165,20 @@ private:
nodep->user1(nodep->isQuad() || nodep->isWide());
}
// Null dereference protection
virtual void visit(AstNullCheck* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
}
virtual void visit(AstCMethodCall* nodep) VL_OVERRIDE {
iterateChildren(nodep);
ensureNullChecked(nodep->fromp());
}
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
iterateChildren(nodep);
ensureNullChecked(nodep->fromp());
}
// NOPs
virtual void visit(AstVar*) VL_OVERRIDE {}

143
src/V3Class.cpp Normal file
View File

@ -0,0 +1,143 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Handle SV classes
//
// 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
//
//*************************************************************************
// V3Class's Transformations:
//
// Each class:
// Move to be modules under AstNetlist
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3Global.h"
#include "V3Class.h"
#include "V3Ast.h"
//######################################################################
class ClassVisitor : public AstNVisitor {
private:
// MEMBERS
AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep; // Package moving scopes into
typedef std::vector<std::pair<AstNode*, AstScope*> > MoveVector;
MoveVector m_moves;
// NODE STATE
// AstClass::user1() -> bool. True if iterated already
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstClass* nodep) VL_OVERRIDE {
if (nodep->user1SetOnce()) return;
// Move this class
nodep->name(m_prefix + nodep->name());
nodep->unlinkFrBack();
v3Global.rootp()->addModulep(nodep);
// Make containing package
// Note origName is the same as the class origName so errors look correct
AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName());
packagep->name(nodep->name() + "__Vclpkg");
nodep->packagep(packagep);
packagep->classp(nodep);
v3Global.rootp()->addModulep(packagep);
// Add package to hierarchy
AstCell* cellp = new AstCell(packagep->fileline(),
packagep->fileline(),
packagep->name(),
packagep->name(),
NULL, NULL, NULL);
cellp->modp(packagep);
v3Global.rootp()->topModulep()->addStmtp(cellp);
// Find class's scope
// Alternative would be to move this and related to V3Scope
AstScope* classScopep = NULL;
for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) {
if ((classScopep = VN_CAST(itp, Scope))) {
break;
}
}
UASSERT_OBJ(classScopep, nodep, "No scope under class");
// Add scope
AstScope* scopep = new AstScope(nodep->fileline(),
packagep, classScopep->name(), classScopep->aboveScopep(),
classScopep->aboveCellp());
packagep->addStmtp(scopep);
// Iterate
string prevPrefix = m_prefix;
{
m_classScopep = classScopep;
m_prefix = nodep->name() + "__02e"; // .
iterateChildren(nodep);
}
m_prefix = prevPrefix;
m_classScopep = NULL;
}
virtual void visit(AstPackage* nodep) VL_OVERRIDE {
string prevPrefix = m_prefix;
{
m_prefix = nodep->name() + "__03a__03a"; // ::
iterateChildren(nodep);
}
m_prefix = prevPrefix;
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move class statics only
//if (m_classScopep) {
// m_moves.push_back(make_pair(nodep, m_classScopep));
//}
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
iterateChildren(nodep);
// Don't move now, or wouldn't keep interating the class
// TODO move function statics only
//if (m_classScopep) {
// m_moves.push_back(make_pair(nodep, m_classScopep));
//}
}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {} // Short circuit
virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE {} // Short circuit
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit ClassVisitor(AstNetlist* nodep)
: m_classScopep(NULL) {
iterate(nodep);
}
virtual ~ClassVisitor() {
for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) {
it->second->addVarp(it->first->unlinkFrBack());
}
}
};
//######################################################################
// Class class functions
void V3Class::classAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClassVisitor visitor(nodep); } // Destruct before checking
V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

33
src/V3Class.h Normal file
View File

@ -0,0 +1,33 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Pre C-Emit stage changes
//
// 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 _V3CLASS_H_
#define _V3CLASS_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
//============================================================================
class V3Class {
public:
static void classAll(AstNetlist* nodep);
};
#endif // Guard

View File

@ -1608,6 +1608,7 @@ private:
&& m_doNConst
&& v3Global.opt.oConst()
// Default value, not a "known" constant for this usage
&& !nodep->varp()->isClassMember()
&& !(nodep->varp()->isFuncLocal()
&& nodep->varp()->isNonOutput())
&& !nodep->varp()->noSubst()

View File

@ -92,6 +92,7 @@ private:
std::vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
std::vector<AstScope*> m_scopesp; // List of all encountered to avoid another loop through tree
std::vector<AstCell*> m_cellsp; // List of all encountered to avoid another loop through tree
std::vector<AstClass*> m_classesp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
bool m_elimUserVars; // Allow removal of user's vars
bool m_elimDTypes; // Allow removal of DTypes
@ -135,6 +136,13 @@ private:
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
if (AstClass* classp = VN_CAST(nodep, Class)) {
if (classp->extendsp()) classp->extendsp()->user1Inc();
if (classp->packagep()) classp->packagep()->user1Inc();
m_classesp.push_back(classp);
// TODO we don't reclaim dead classes yet - graph implementation instead?
classp->user1Inc();
}
}
}
m_modp = origModp;
@ -148,7 +156,9 @@ private:
iterateChildren(nodep);
checkAll(nodep);
if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc();
// Class packages might have no children, but need to remain as
// long as the class they refer to is needed
if (VN_IS(m_modp, Class) || VN_IS(m_modp, ClassPackage)) nodep->user1Inc();
if (!nodep->isTop() && !nodep->varsp() && !nodep->blocksp() && !nodep->finalClksp()) {
m_scopesp.push_back(nodep);
}
@ -196,6 +206,18 @@ private:
else nodep->packagep()->user1Inc();
}
}
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkDType(nodep);
checkAll(nodep);
if (nodep->packagep()) {
if (m_elimCells) nodep->packagep(NULL);
else nodep->packagep()->user1Inc();
}
if (nodep->classp()) {
nodep->classp()->user1Inc();
}
}
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
iterateChildren(nodep);
checkDType(nodep);
@ -342,6 +364,23 @@ private:
}
}
}
void deadCheckClasses() {
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstClass*>::iterator it = m_classesp.begin(); it != m_classesp.end();
++it) {
if (AstClass* nodep = *it) { // NULL if deleted earlier
if (nodep->user1() == 0) {
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
if (nodep->packagep()) nodep->packagep()->user1Inc(-1);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
*it = NULL;
retry = true;
}
}
}
}
}
void deadCheckVar() {
// Delete any unused varscopes
@ -422,6 +461,7 @@ public:
// Otherwise we have no easy way to know if a scope is used
if (elimScopes) deadCheckScope();
if (elimCells) deadCheckCells();
deadCheckClasses();
// Modules after vars, because might be vars we delete inside a mod we delete
deadCheckMod();

View File

@ -109,6 +109,9 @@ private:
// The risk that this prevents combining identical logic from differently-
// named but identical modules seems low.
if (m_modSingleton) relativeRefOk = false;
//
// Class methods need relative
if (m_modp && VN_IS(m_modp, Class)) relativeRefOk = true;
if (varp && varp->isFuncLocal()) {
hierThisr = true;

View File

@ -829,9 +829,29 @@ public:
iterateAndNextNull(nodep->expr2p()); puts(")");
}
}
virtual void visit(AstMemberSel* nodep) VL_OVERRIDE {
iterateAndNextNull(nodep->fromp());
putbs("->");
puts(nodep->varp()->nameProtect());
}
virtual void visit(AstNullCheck* nodep) VL_OVERRIDE {
puts("VL_NULL_CHECK(");
iterateAndNextNull(nodep->lhsp());
puts(", ");
putsQuoted(protect(nodep->fileline()->filename()));
puts(", ");
puts(cvtToStr(nodep->fileline()->lineno()));
puts(")");
}
virtual void visit(AstNew* nodep) VL_OVERRIDE {
puts("std::make_shared<" + nodep->dtypep()->nameProtect() + ">(");
iterateChildren(nodep);
puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">(");
iterateAndNextNull(nodep->argsp());
puts(")");
}
virtual void visit(AstNewCopy* nodep) VL_OVERRIDE {
puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">(");
puts("*"); // i.e. make into a reference
iterateAndNextNull(nodep->rhsp());
puts(")");
}
virtual void visit(AstSel* nodep) VL_OVERRIDE {
@ -1505,6 +1525,9 @@ class EmitCImp : EmitCStmts {
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1,
".atDefault()" + cvtarray);
}
else if (AstClassRefDType* adtypep = VN_CAST(dtypep, ClassRefDType)) {
return ""; // Constructor does it
}
else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, ".atDefault()");
}
@ -2723,7 +2746,11 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n//----------\n\n");
emitTextSection(AstType::atScHdr);
if (optSystemC() && modp->isTop()) {
if (AstClass* classp = VN_CAST(modp, Class)) {
puts("class " + prefixNameProtect(modp));
if (classp->extendsp()) puts(" : public " + classp->extendsp()->classp()->nameProtect());
puts(" {\n");
} else if (optSystemC() && modp->isTop()) {
puts("SC_MODULE(" + prefixNameProtect(modp) + ") {\n");
} else {
puts("VL_MODULE(" + prefixNameProtect(modp) + ") {\n");
@ -2832,7 +2859,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("/// The special name "" may be used to make a wrapper with a\n");
puts("/// single model invisible with respect to DPI scope names.\n");
}
puts(prefixNameProtect(modp) + "(const char* name = \"TOP\");\n");
if (VN_IS(modp, Class)) {
// TODO move all constructor definition to e.g. V3CUse
puts(prefixNameProtect(modp) + "();\n");
} else {
puts(prefixNameProtect(modp) + "(const char* name = \"TOP\");\n");
}
if (modp->isTop()) {
puts("/// Destroy the model; called (often implicitly) by application code\n");
}
@ -2889,6 +2921,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("void " + protect("__Vconfigure") + "(" + symClassName() + "* symsp, bool first);\n");
}
ofp()->putsPrivate(false); // public:
emitIntFuncDecls(modp, true);
if (v3Global.opt.trace() && !VN_IS(modp, Class)) {
@ -2996,6 +3029,12 @@ void EmitCImp::mainInt(AstNodeModule* modp) {
m_ofp = newOutCFile(fileModp, false/*slow*/, false/*source*/);
emitIntTop(modp);
emitInt(modp);
if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) {
// Put the non-static class implementation in same h file for speed
m_modp = packagep->classp();
emitInt(packagep->classp());
m_modp = modp;
}
ofp()->putsEndGuard();
VL_DO_CLEAR(delete m_ofp, m_ofp = NULL);
}
@ -3013,6 +3052,15 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow, bool fast) {
emitImpTop(fileModp);
emitImp(modp);
if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) {
// Put the non-static class implementation in same C++ files as
// often optimizations are possible when both are seen by the
// compiler together
m_modp = packagep->classp();
emitImp(packagep->classp());
m_modp = modp;
}
if (fast && modp->isTop() && v3Global.opt.mtasks()) {
// Make a final pass and emit function definitions for the mtasks
// in the ExecGraph
@ -3489,6 +3537,7 @@ void V3EmitC::emitc() {
// Process each module in turn
for (AstNodeModule* nodep = v3Global.rootp()->modulesp();
nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage
{ EmitCImp cint; cint.mainInt(nodep); }
if (v3Global.opt.outputSplit()) {
{ EmitCImp fast; fast.mainImp(nodep, false, true); }

View File

@ -46,6 +46,11 @@ class EmitCInlines : EmitCBaseVisitor {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
v3Global.needC11(true);
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
v3Global.needHeavy(true);
iterateChildren(nodep);

View File

@ -283,6 +283,7 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible
nameCheck(nodep);
m_scopes.push_back(make_pair(nodep, m_modp));
@ -381,6 +382,7 @@ void EmitCSyms::emitSymHdr() {
puts("\n// INCLUDE MODULE CLASSES\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Class included earlier
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
@ -422,6 +424,7 @@ void EmitCSyms::emitSymHdr() {
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first;
AstNodeModule* modp = it->second;
if (VN_IS(modp, Class)) continue;
if (modp->isTop()) {
ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str());
puts(protectIf(scopep->nameDotless() + "p", scopep->protect()) + ";\n");
@ -528,6 +531,7 @@ void EmitCSyms::emitSymImpPreamble() {
puts("#include \""+symClassName()+".h\"\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Class included earlier
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
}

View File

@ -114,6 +114,12 @@ private:
iterateChildren(nodep);
m_modp = NULL;
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
// TODO allow inlining of modules that have classes
// (Probably wait for new inliner scheme)
cantInline("class", true);
iterateChildren(nodep);
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
nodep->modp()->user3Inc(); // Inc refs
m_instances[m_modp][nodep->modp()]++;
@ -294,6 +300,11 @@ private:
nodep->name(name);
iterateChildren(nodep);
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
string name = m_cellp->name() + "__DOT__" + nodep->name();
nodep->name(name);
iterateChildren(nodep);
}
virtual void visit(AstModule* nodep) VL_OVERRIDE {
m_renamedInterfaces.clear();
iterateChildren(nodep);
@ -376,7 +387,7 @@ private:
// Variable under the inline cell, need to rename to avoid conflicts
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (!nodep->isFuncLocal() && !nodep->isClassMember()) nodep->inlineAttrReset(name);
if (!m_cellp->isTrace()) nodep->trace(false);
if (debug() >= 9) { nodep->dumpTree(cout, "varchanged:"); }
if (debug() >= 9 && nodep->valuep()) { nodep->valuep()->dumpTree(cout, "varchangei:"); }

View File

@ -325,6 +325,10 @@ public:
if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
void insertMap(VSymEnt* symp, const string& scopename) {
if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
}
VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* modSymp,
AstCellInline* nodep, const string& basename) {
// A fake point in the hierarchy, corresponding to an inlined module
@ -816,6 +820,39 @@ class LinkDotFindVisitor : public AstNVisitor {
// Prep for next
m_packagep = NULL;
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
UINFO(8," "<<nodep<<endl);
string oldscope = m_scope;
VSymEnt* oldModSymp = m_modSymp;
VSymEnt* oldCurSymp = m_curSymp;
int oldParamNum = m_paramNum;
int oldBeginNum = m_beginNum;
int oldModBeginNum = m_modBeginNum;
{
UINFO(4," Link Class: "<<nodep<<endl);
VSymEnt* upperSymp = m_curSymp;
m_scope = m_scope + "." + nodep->name();
m_curSymp = m_modSymp
= m_statep->insertBlock(upperSymp, nodep->name(), nodep, m_packagep);
m_statep->insertMap(m_curSymp, m_scope);
UINFO(9, "New module scope "<<m_curSymp<<endl);
//
m_paramNum = 0;
m_beginNum = 0;
m_modBeginNum = 0;
// m_modSymp/m_curSymp for non-packages set by AstCell above this module
// Iterate
iterateChildren(nodep);
nodep->user4(true);
}
m_scope = oldscope;
m_modSymp = oldModSymp;
m_curSymp = oldCurSymp;
m_paramNum = oldParamNum;
m_beginNum = oldBeginNum;
m_modBeginNum = oldModBeginNum;
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UASSERT_OBJ(m_statep->forScopeCreation(), nodep,
"Scopes should only exist right after V3Scope");
@ -1400,7 +1437,7 @@ class LinkDotScopeVisitor : public AstNVisitor {
m_scopep = NULL;
}
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
if (!nodep->varp()->isFuncLocal()) {
if (!nodep->varp()->isFuncLocal() && !nodep->varp()->isClassMember()) {
VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
if (nodep->varp()->isIfaceRef()
&& nodep->varp()->isIfaceParent()) {
@ -2484,6 +2521,44 @@ private:
m_ds.m_dotSymp = m_curSymp = oldCurSymp;
m_ftaskp = NULL;
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (AstClassExtends* eitemp = VN_CAST(itemp, ClassExtends)) {
// Replace abstract reference with hard pointer
// Will need later resolution when deal with parameters
eitemp->v3error("Unsupported: class extends");
}
}
VSymEnt* oldCurSymp = m_curSymp;
VSymEnt* oldModSymp = m_modSymp;
{
m_ds.init(m_curSymp);
// Until overridden by a SCOPE
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep);
m_modp = nodep;
iterateChildren(nodep);
}
// V3Width when determines types needs to find enum values and such
// so add members pointing to appropriate enum values
{
nodep->repairCache();
for (VSymEnt::const_iterator it = m_curSymp->begin(); it != m_curSymp->end(); ++it) {
AstNode* itemp = it->second->nodep();
if (!nodep->findMember(it->first)) {
if (AstEnumItem* aitemp = VN_CAST(itemp, EnumItem)) {
AstEnumItemRef* newp = new AstEnumItemRef(aitemp->fileline(), aitemp,
it->second->packagep());
UINFO(8, "Class import noderef '" << it->first << "' " << newp << endl);
nodep->addMembersp(newp);
}
}
}
}
m_curSymp = oldCurSymp;
m_modSymp = oldModSymp;
}
virtual void visit(AstRefDType* nodep) VL_OVERRIDE {
// Resolve its reference
if (nodep->user3SetOnce()) return;
@ -2515,8 +2590,16 @@ private:
nodep->refDTypep(defp);
nodep->packagep(foundp->packagep());
}
else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : NULL) {
AstClassRefDType* newp = new AstClassRefDType(nodep->fileline(), defp);
newp->packagep(foundp->packagep());
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
return;
}
else {
nodep->v3error("Can't find typedef: "<<nodep->prettyNameQ());
if (foundp) UINFO(1, "Found sym node: " << foundp->nodep() << endl);
nodep->v3error("Can't find typedef: " << nodep->prettyNameQ());
}
}
iterateChildren(nodep);

View File

@ -219,12 +219,18 @@ private:
if (nodep->valuep()) {
// A variable with an = value can be three things:
FileLine* fl = nodep->valuep()->fileline();
// 1. Parameters and function inputs: It's a default to use if not overridden
if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) {
}
else if (!m_ftaskp && nodep->isNonOutput()) {
nodep->v3error("Unsupported: Default value on module input: "
<<nodep->prettyNameQ());
// 1. Parameters and function inputs: It's a default to use if not overridden
} else if (VN_IS(m_modp, Class)) {
// We make a AstVar initial value, but then do not set it in the constructor
// V3Emit::emitVarRecurse only does non-value inits.
// Perhaps these should still become a new form of
// AstInitial, and we propagate the initial to the class
// constructor
nodep->valuep()->v3error("Unsupported: initial value on member");
} else if (!m_ftaskp && nodep->isNonOutput()) {
nodep->v3error(
"Unsupported: Default value on module input: " << nodep->prettyNameQ());
nodep->valuep()->unlinkFrBack()->deleteTree();
} // 2. Under modules, it's an initial value to be loaded at time 0 via an AstInitial
else if (m_valueModp) {

View File

@ -50,6 +50,7 @@ private:
// STATE
// Below state needs to be preserved between each module call.
AstNodeModule* m_modp; // Current module
AstClass* m_classp; // Class we're inside
AstNodeFTask* m_ftaskp; // Function or task we're inside
AstNodeCoverOrAssert* m_assertp; // Current assertion
int m_senitemCvtNum; // Temporary signal counter
@ -89,9 +90,17 @@ private:
iterateChildren(nodep);
m_assertp = NULL;
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
AstClass* origClassp = m_classp;
{
m_classp = nodep;
iterateChildren(nodep);
}
m_classp = origClassp;
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_classp) nodep->classMember(true);
if (m_ftaskp) nodep->funcLocal(true);
if (nodep->isSigModPublic()) {
nodep->sigModPublic(false); // We're done with this attribute
@ -110,6 +119,7 @@ private:
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
// NodeTask: Remember its name for later resolution
// Remember the existing symbol table scope
if (m_classp) nodep->classMethod(true);
m_ftaskp = nodep;
iterateChildren(nodep);
m_ftaskp = NULL;
@ -458,6 +468,7 @@ private:
public:
// CONSTRUCTORS
explicit LinkResolveVisitor(AstNetlist* rootp) {
m_classp = NULL;
m_ftaskp = NULL;
m_modp = NULL;
m_assertp = NULL;

View File

@ -82,7 +82,7 @@ private:
// Add __PVT__ to names of local signals
virtual void visit(AstVar* nodep) VL_OVERRIDE {
// Don't iterate... Don't need temps for RANGES under the Var.
rename(nodep, (!m_modp->isTop()
rename(nodep, ((!m_modp || !m_modp->isTop())
&& !nodep->isSigPublic()
&& !nodep->isFuncLocal() // Isn't exposed, and would mess up dpi import wrappers
&& !nodep->isTemp())); // Don't bother to rename internal signals
@ -101,7 +101,8 @@ private:
}
virtual void visit(AstCell* nodep) VL_OVERRIDE {
if (!nodep->user1()) {
rename(nodep, !nodep->modp()->modPublic());
rename(nodep, (!nodep->modp()->modPublic()
&& !VN_IS(nodep->modp(), ClassPackage)));
iterateChildren(nodep);
}
}
@ -121,10 +122,13 @@ private:
if (!nodep->user1SetOnce()) {
if (nodep->aboveScopep()) iterate(nodep->aboveScopep());
if (nodep->aboveCellp()) iterate(nodep->aboveCellp());
// Always recompute name (as many level above scope may have changed)
// Always recompute name (as many levels above scope may have changed)
// Same formula as V3Scope
nodep->name(nodep->isTop() ? "TOP"
: (nodep->aboveScopep()->name()+"."+nodep->aboveCellp()->name()));
: VN_IS(m_modp, Class) ? ("TOP." + m_modp->name())
: VN_IS(m_modp, ClassPackage) ? ("TOP." + m_modp->name())
: (nodep->aboveScopep()->name() + "." + nodep->aboveCellp()->name()));
nodep->editCountInc();
iterateChildren(nodep);
}
}

View File

@ -1018,6 +1018,7 @@ private:
}
m_modp = origModp;
}
virtual void visit(AstClass*) VL_OVERRIDE {}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
UINFO(4," SCOPE "<<nodep<<endl);
m_scopep = nodep;

View File

@ -71,7 +71,8 @@ private:
it!=m_varRefScopes.end(); ++it) {
AstVarRef* nodep = it->first;
AstScope* scopep = it->second;
if (nodep->packagep()) {
if (nodep->packagep()
&& !nodep->varp()->isClassMember()) {
PackageScopeMap::iterator it2 = m_packageScopes.find(nodep->packagep());
UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope");
scopep = it2->second;
@ -147,6 +148,39 @@ private:
// ***Note m_scopep is passed back to the caller of the routine (above)
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
// Create required blocks and add to module
AstScope* oldScopep = m_scopep;
AstCell* oldAbCellp = m_aboveCellp;
AstScope* oldAbScopep = m_aboveScopep;
{
m_aboveScopep = m_scopep;
string scopename;
if (!m_aboveScopep) {
scopename = "TOP";
} else {
scopename = m_aboveScopep->name() + "." + nodep->name();
}
UINFO(4, " CLASS AT " << scopename << " " << nodep << endl);
AstNode::user1ClearTree();
AstNode* abovep = (m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp)
: static_cast<AstNode*>(nodep));
m_scopep = new AstScope(abovep->fileline(),
m_modp, scopename, m_aboveScopep, m_aboveCellp);
// Create scope for the current usage of this cell
AstNode::user1ClearTree();
nodep->addMembersp(m_scopep);
iterateChildren(nodep);
}
// Done, restore vars
m_scopep = oldScopep;
m_aboveCellp = oldAbCellp;
m_aboveScopep = oldAbScopep;
}
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
nodep->scopep(m_scopep);
}
@ -230,7 +264,14 @@ private:
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
// Add to list of blocks under this scope
UINFO(4," FTASK "<<nodep<<endl);
AstNodeFTask* clonep = nodep->cloneTree(false);
AstNodeFTask* clonep;
if (nodep->classMethod()) {
// Only one scope will be created, so avoid pointless cloning
nodep->unlinkFrBack();
clonep = nodep;
} else {
clonep = nodep->cloneTree(false);
}
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
// We iterate under the *clone*
@ -238,7 +279,6 @@ private:
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
// Make new scope variable
// This is called cross-module by AstVar, so we cannot trust any m_ variables
if (!nodep->user1p()) {
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
UINFO(6," New scope "<<varscp<<endl);

View File

@ -41,7 +41,6 @@ typedef std::set<const VSymEnt*> VSymConstMap;
class VSymEnt {
// Symbol table that can have a "superior" table for resolving upper references
private:
// MEMBERS
typedef std::multimap<string,VSymEnt*> IdNameMap;
IdNameMap m_idNameMap; // Hash of variables by name
@ -62,6 +61,11 @@ private:
static inline int debug() { return 0; } // NOT runtime, too hot of a function
#endif
public:
typedef IdNameMap::const_iterator const_iterator;
const_iterator begin() const { return m_idNameMap.begin(); }
const_iterator end() const { return m_idNameMap.end(); }
void dumpIterate(std::ostream& os, VSymConstMap& doneSymsr, const string& indent,
int numLevels, const string& searchName) const {
os<<indent<<"+ "<<std::left<<std::setw(30)

View File

@ -203,6 +203,7 @@ private:
TaskBaseVertex* lastVxp = m_curVxp;
m_curVxp = getFTaskVertex(nodep);
if (nodep->dpiImport()) m_curVxp->noInline(true);
if (nodep->classMethod()) m_curVxp->noInline(true); // Until V3Task supports it
iterateChildren(nodep);
m_curVxp = lastVxp;
}
@ -993,7 +994,7 @@ private:
cfuncp->funcPublic(nodep->taskPublic());
cfuncp->dpiExport(nodep->dpiExport());
cfuncp->dpiImportWrapper(nodep->dpiImport());
cfuncp->isStatic(!(nodep->dpiImport()||nodep->taskPublic()));
cfuncp->isStatic(!(nodep->dpiImport() || nodep->taskPublic() || nodep->classMethod()));
cfuncp->pure(nodep->pure());
//cfuncp->dpiImport // Not set in the wrapper - the called function has it set
if (cfuncp->dpiExport()) cfuncp->cname(nodep->cname());
@ -1206,19 +1207,25 @@ private:
if (nodep->dpiImport()) modes++;
if (nodep->dpiExport()) modes++;
if (nodep->taskPublic()) modes++;
if (nodep->classMethod()) modes++;
if (v3Global.opt.protectIds() && nodep->taskPublic()) {
// 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.
nodep->v3error("Unsupported: Using --protect-ids with public function");
}
if (modes > 1) nodep->v3error("Cannot mix DPI import, DPI export and/or public on same function: "
<<nodep->prettyNameQ());
if (modes > 1) {
nodep->v3error("Cannot mix DPI import, DPI export, class methods, and/or public "
"on same function: "
<< nodep->prettyNameQ());
}
if (nodep->dpiImport() || nodep->dpiExport()
|| nodep->taskPublic() || m_statep->ftaskNoInline(nodep)) {
if (nodep->dpiImport() || nodep->dpiExport() || nodep->taskPublic()
|| m_statep->ftaskNoInline(nodep)) {
// Clone it first, because we may have later FTaskRef's that still need
// the original version.
if (m_statep->ftaskNoInline(nodep)) m_statep->checkPurity(nodep);
if (m_statep->ftaskNoInline(nodep) && !nodep->classMethod()) {
m_statep->checkPurity(nodep);
}
AstNodeFTask* clonedFuncp = nodep->cloneTree(false);
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, m_statep->ftaskNoInline(nodep));
if (cfuncp) {

View File

@ -195,6 +195,7 @@ private:
// Generally this equation doesn't need updating, instead use
// varp->isTrace() and/or vscIgnoreTrace.
if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace())
&& !nodep->varp()->isClassMember()
&& !nodep->varp()->isFuncLocal()) {
UINFO(5, " vsc "<<nodep<<endl);
AstVar* varp = nodep->varp();

View File

@ -1338,6 +1338,9 @@ class TristateVisitor : public TristateBaseVisitor {
m_tgraph.clear(); // Recursion not supported
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
// don't deal with classes
}
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
// don't deal with functions
}

View File

@ -336,6 +336,7 @@ private:
&& !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items
if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable()
&& !nodep->varp()->isDeclTyped()
&& !nodep->varp()->isClassMember()
&& !nodep->varp()->isFuncLocal()) {
nodep->v3warn(PROCASSWIRE, "Procedural assignment to wire, perhaps intended var"
<< " (IEEE 1800-2017 6.5): " << nodep->prettyNameQ());

View File

@ -1769,6 +1769,19 @@ private:
nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration
//if (debug()>=9) nodep->dumpTree("-class-out-");
}
virtual void visit(AstClass* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
userIterateChildren(nodep, NULL); // First size all members
nodep->repairCache();
}
virtual void visit(AstClassExtends* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
if (nodep->childDTypep()) {
nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
}
nodep->v3error("Unsupported: class extends"); // Member/meth access breaks
userIterateChildren(nodep, NULL);
}
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
@ -1788,6 +1801,23 @@ private:
UINFO(9," from dt "<<fromDtp<<endl);
if (AstNodeUOrStructDType* adtypep = VN_CAST(fromDtp, NodeUOrStructDType)) {
if (memberSelStruct(nodep, adtypep)) return;
} else if (AstClassRefDType* adtypep = VN_CAST(fromDtp, ClassRefDType)) {
if (AstNode* foundp = memberSelClass(nodep, adtypep)) {
if (AstVar* varp = VN_CAST(foundp, Var)) {
nodep->dtypep(foundp->dtypep());
nodep->varp(varp);
return;
}
if (AstEnumItemRef* adfoundp = VN_CAST(foundp, EnumItemRef)) {
nodep->replaceWith(adfoundp->cloneTree(false));
return;
}
UINFO(1, "found object " << foundp << endl);
nodep->v3fatalSrc("MemberSel of non-variable\n"
<< nodep->warnContextPrimary() << endl
<< foundp->warnOther() << "... Location of found object\n"
<< foundp->warnContextSecondary());
}
} else if (VN_IS(fromDtp, EnumDType)
|| VN_IS(fromDtp, AssocArrayDType)
|| VN_IS(fromDtp, DynArrayDType)
@ -1810,6 +1840,30 @@ private:
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse()));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
AstNode* memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) {
// Returns node if ok
// No need to width-resolve the class, as it was done when we did the child
AstClass* first_classp = adtypep->classp();
UASSERT_OBJ(first_classp, nodep, "Unlinked");
for (AstClass* classp = first_classp; classp;) {
if (AstNode* foundp = classp->findMember(nodep->name())) return foundp;
classp = classp->extendsp() ? classp->extendsp()->classp() : NULL;
}
VSpellCheck speller;
for (AstClass* classp = first_classp; classp;) {
for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var) || VN_IS(itemp, EnumItemRef)) {
speller.pushCandidate(itemp->prettyName());
}
}
classp = classp->extendsp() ? classp->extendsp()->classp() : NULL;
}
string suggest = speller.bestCandidateMsg(nodep->prettyName());
nodep->v3error("Member "<<nodep->prettyNameQ()<<" not found in class "
<<first_classp->prettyNameQ()<<"\n"
<<(suggest.empty() ? "" : nodep->fileline()->warnMore()+suggest));
return NULL; // Caller handles error
}
bool memberSelStruct(AstMemberSel* nodep, AstNodeUOrStructDType* adtypep) {
// Returns true if ok
if (AstMemberDType* memberp = adtypep->findMember(nodep->name())) {
@ -1868,6 +1922,9 @@ private:
else if (AstQueueDType* adtypep = VN_CAST(fromDtp, QueueDType)) {
methodCallQueue(nodep, adtypep);
}
else if (AstClassRefDType* adtypep = VN_CAST(fromDtp, ClassRefDType)) {
methodCallClass(nodep, adtypep);
}
else if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
methodCallUnpack(nodep, adtypep);
}
@ -2218,6 +2275,35 @@ private:
VL_DANGLING(index_exprp); // May have been edited
return VN_CAST(nodep->pinsp(), Arg)->exprp();
}
void methodCallClass(AstMethodCall* nodep, AstClassRefDType* adtypep) {
// No need to width-resolve the class, as it was done when we did the child
AstClass* first_classp = adtypep->classp();
UASSERT_OBJ(first_classp, nodep, "Unlinked");
for (AstClass* classp = first_classp; classp;) {
if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
nodep->taskp(ftaskp);
nodep->dtypeFrom(ftaskp);
if (VN_IS(ftaskp, Task)) nodep->makeStatement();
return;
}
classp = classp->extendsp() ? classp->extendsp()->classp() : NULL;
}
{
VSpellCheck speller;
for (AstClass* classp = first_classp; classp;) {
for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, NodeFTask)) speller.pushCandidate(itemp->prettyName());
}
classp = classp->extendsp() ? classp->extendsp()->classp() : NULL;
}
string suggest = speller.bestCandidateMsg(nodep->prettyName());
nodep->v3error("Class method "
<< nodep->prettyNameQ() << " not found in class "
<< first_classp->prettyNameQ() << "\n"
<< (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest));
}
nodep->dtypeSetSigned32(); // Guess on error
}
void methodCallUnpack(AstMethodCall* nodep, AstUnpackArrayDType* adtypep) {
enum { UNKNOWN = 0, ARRAY_OR, ARRAY_AND, ARRAY_XOR } methodId;
@ -2347,12 +2433,25 @@ private:
nodep->dtypep(refp);
if (nodep->argsp()) {
nodep->v3error("Unsupported: new with arguments");
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
pushDeletep(nodep->argsp()->unlinkFrBackWithNext());
//TODO code similar to AstNodeFTaskRef
//userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
}
}
virtual void visit(AstNewCopy* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
nodep->v3error("Unsupported: new-as-copy");
AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType);
if (!refp) { // e.g. int a = new;
nodep->v3error("new() not expected in this context");
return;
}
nodep->dtypep(refp);
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
if (!similarDTypeRecurse(nodep->dtypep(), nodep->rhsp()->dtypep())) {
nodep->rhsp()->v3error("New-as-copier passed different data type '"
<< nodep->dtypep()->prettyTypeName() << "' then expected '"
<< nodep->rhsp()->dtypep()->prettyTypeName() << "'");
}
}
virtual void visit(AstNewDynamic* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
@ -2866,6 +2965,7 @@ private:
added = true;
newFormat += "%g";
} else if (VN_IS(dtypep, AssocArrayDType)
|| VN_IS(dtypep, ClassRefDType)
|| VN_IS(dtypep, DynArrayDType)
|| VN_IS(dtypep, QueueDType)) {
added = true;
@ -3297,7 +3397,11 @@ private:
nodep->doingWidth(true); // Would use user1 etc, but V3Width called from too many places to spend a user
m_ftaskp = nodep;
userIterateChildren(nodep, NULL);
if (nodep->fvarp()) {
if (nodep->isConstructor()) {
// Pretend it's void so less special casing needed when look at dtypes
nodep->v3error("Unsupported: new constructor");
nodep->dtypeSetVoid();
} else if (nodep->fvarp()) {
m_funcp = VN_CAST(nodep, Func);
UASSERT_OBJ(m_funcp, nodep, "FTask with function variable, but isn't a function");
nodep->dtypeFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep()

View File

@ -26,6 +26,7 @@
#include "V3Case.h"
#include "V3Cast.h"
#include "V3Changed.h"
#include "V3Class.h"
#include "V3Clean.h"
#include "V3Clock.h"
#include "V3Combine.h"
@ -228,6 +229,9 @@ static void process() {
// Flatten hierarchy, creating a SCOPE for each module's usage as a cell
V3Scope::scopeAll(v3Global.rootp());
V3LinkDot::linkDotScope(v3Global.rootp());
// Relocate classes (after linkDot)
V3Class::classAll(v3Global.rootp());
}
//--SCOPE BASED OPTIMIZATIONS--------------

View File

@ -3532,15 +3532,16 @@ funcId<ftaskp>: // IEEE: function_data_type_or_implicit + part of function_bod
funcIdNew<ftaskp>: // IEEE: from class_constructor_declaration
yNEW__ETC
{ $$ = new AstFunc($<fl>1, "new", NULL, NULL);
BBUNSUP($<fl>1, "Unsupported: new constructor");
$$->isConstructor(true);
SYMP->pushNewUnder($$, NULL); }
| yNEW__PAREN
{ $$ = new AstFunc($<fl>1, "new", NULL, NULL);
BBUNSUP($<fl>1, "Unsupported: new constructor");
$$->isConstructor(true);
SYMP->pushNewUnder($$, NULL); }
| class_scopeWithoutId yNEW__PAREN
{ $$ = new AstFunc($<fl>2, "new", NULL, NULL);
BBUNSUP($<fl>2, "Unsupported: scoped new constructor");
$$->isConstructor(true);
SYMP->pushNewUnder($$, NULL); }
;
@ -5435,7 +5436,9 @@ class_declaration<nodep>: // ==IEEE: part of class_declaration
classFront parameter_port_listE classExtendsE classImplementsE ';'
class_itemListE yENDCLASS endLabelE
{ $$ = $1; $1->addMembersp($2);
$1->addMembersp($4); $1->addMembersp($6);
$1->extendsp($3);
$1->addMembersp($4);
$1->addMembersp($6);
SYMP->popScope($$);
GRAMMARP->endLabel($<fl>7, $1, $8); }
;
@ -5443,8 +5446,7 @@ class_declaration<nodep>: // ==IEEE: part of class_declaration
classFront<classp>: // IEEE: part of class_declaration
classVirtualE yCLASS lifetimeE idAny/*class_identifier*/
{ $$ = new AstClass($2, *$4);
SYMP->pushNew($<classp>$);
BBUNSUP($2, "Unsupported: classes"); }
SYMP->pushNew($<classp>$); }
// // IEEE: part of interface_class_declaration
| yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/
{ $$ = new AstClass($2, *$4);
@ -5473,10 +5475,11 @@ classExtendsList<nodep>: // IEEE: part of class_declaration
classExtendsOne<nodep>: // IEEE: part of class_declaration
class_typeWithoutId
{ $$ = NULL; BBUNSUP($1, "Unsupported: extends"); }
{ $$ = new AstClassExtends($1->fileline(), $1); }
// // IEEE: Might not be legal to have more than one set of parameters in an extends
| class_typeWithoutId '(' list_of_argumentsE ')'
{ $$ = NULL; BBUNSUP($1, "Unsupported: extends"); }
{ $$ = new AstClassExtends($1->fileline(), $1);
if ($3) BBUNSUP($3, "Unsupported: extends with parameters"); }
;
classImplementsE<nodep>: // IEEE: part of class_declaration

View File

@ -0,0 +1,4 @@
Display: null = "null"
Display: newed = "`{imembera:'h0, imemberb:'h0}"
Display: set = "`{imembera:'ha, imemberb:'h14}"
*-* All Finished *-*

22
test_regress/t/t_class1.pl Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

29
test_regress/t/t_class1.v Normal file
View File

@ -0,0 +1,29 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
typedef class Cls;
class Cls;
int imembera;
int imemberb;
endclass : Cls
module t (/*AUTOARG*/);
initial begin
Cls c;
if (c != null) $stop;
$display("Display: null = \"%p\"", c); // null
c = new;
$display("Display: newed = \"%p\"", c); // '{imembera:0, imemberb:0}
c.imembera = 10;
c.imemberb = 20;
$display("Display: set = \"%p\"", c); // '{imembera:10, imemberb:20}
if (c.imembera != 10) $stop;
if (c.imemberb != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,10 @@
%Error: t/t_class2.v:35:14: Unsupported: Hierarchical class references
35 | if (Cls::ENUM_VAL != 22) $stop;
| ^~
%Error: t/t_class2.v:35:16: Unsupported: scoped class reference
35 | if (Cls::ENUM_VAL != 22) $stop;
| ^~~~~~~~
%Error: t/t_class2.v:34:11: Unsupported: scoped class reference
34 | if (Pkg::ENUMP_VAL != 33) $stop;
| ^~~
%Error: Exiting due to

25
test_regress/t/t_class2.pl Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
#
#file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/Dead/x);
ok(1);
1;

40
test_regress/t/t_class2.v Normal file
View File

@ -0,0 +1,40 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
package Pkg;
typedef enum { ENUMP_VAL = 33 } enump_t;
endpackage
module t (/*AUTOARG*/);
class Cls;
int imembera;
int imemberb;
typedef enum { ENUM_VAL = 22 } enum_t;
endclass : Cls
Cls c;
Cls d;
initial begin
// Alternate between two versions to make sure we don't
// constant propagate between them.
c = new;
d = new;
c.imembera = 10;
d.imembera = 11;
c.imemberb = 20;
d.imemberb = 21;
if (c.imembera != 10) $stop;
if (d.imembera != 11) $stop;
if (c.imemberb != 20) $stop;
if (d.imemberb != 21) $stop;
if (Pkg::ENUMP_VAL != 33) $stop;
if (Cls::ENUM_VAL != 22) $stop;
if (c.ENUM_VAL != 22) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_class_class.v:12:4: Unsupported: class within class
12 | class SubCls;
| ^~~~~
%Error: Exiting due to

19
test_regress/t/t_class_class.pl Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,34 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// Note UVM internals do not require classes-in-classes
package P;
class Cls;
int imembera;
int imemberb;
class SubCls;
int smembera;
int smemberb;
endclass : SubCls
SubCls sc;
endclass : Cls
endpackage : P
module t (/*AUTOARG*/);
P::Cls c;
initial begin
c = new;
c.imembera = 10;
c.imemberb = 20;
c.sc = new;
c.sc.smembera = 30;
c.sc.smemberb = 40;
if (c.imembera != 10) $stop;
if (c.imemberb != 20) $stop;
if (c.sc.smembera != 30) $stop;
if (c.sc.smemberb != 40) $stop;
end
endmodule

21
test_regress/t/t_class_copy.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,37 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Cls;
int imembera;
function int inc_methoda; imembera += 1; return imembera; endfunction
endclass
module t (/*AUTOARG*/);
initial begin
Cls c1;
Cls c2;
Cls c3;
c1 = new;
c1.imembera = 10;
if (c1.inc_methoda() != 11) $stop;
// Assignment
c2 = c1;
if (c1.inc_methoda() != 12) $stop;
if (c2.inc_methoda() != 13) $stop;
if (c1.inc_methoda() != 14) $stop;
// Shallow copy
c3 = new c1;
if (c1.inc_methoda() != 15) $stop;
if (c3.inc_methoda() != 15) $stop;
if (c1.inc_methoda() != 16) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,5 @@
%Error: t/t_class_copy_bad.v:19:16: New-as-copier passed different data type 'CLASSREFDTYPE 'Cls'' then expected 'CLASSREFDTYPE 'Other''
: ... In instance t
19 | c1 = new co;
| ^~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,21 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Other;
endclass
class Cls;
int imembera;
function int inc_methoda; imembera += 1; return imembera; endfunction
endclass
module t (/*AUTOARG*/);
initial begin
Cls c1;
Other co;
c1 = new co; // Bad, incompatible types
end
endmodule

25
test_regress/t/t_class_dead.pl Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
$Self->{vlt_all} and unsupported("Verilator unsupported, class dead");
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/dead/ix);
ok(1);
1;

View File

@ -0,0 +1,30 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class EmptyClass_Dead;
endclass
module Mod_Dead;
class ModClass_Dead;
int memberb_dead;
endclass
endmodule
//TODO dead check with class extends
module t (/*AUTOARG*/);
generate
if (0) begin
Mod_Dead cell_dead();
end
endgenerate
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

21
test_regress/t/t_class_enum.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,19 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
class Cls;
typedef enum {A = 10, B = 20, C = 30} en_t;
endclass
initial begin
Cls c;
if (c.A != 10) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,10 @@
%Error: t/t_class_extends.v:13:21: Unsupported: class extends
13 | class Base1 extends Base0;
| ^~~~~
%Error: t/t_class_extends.v:17:21: Unsupported: class extends
17 | class Base2 extends Base1;
| ^~~~~
%Error: t/t_class_extends.v:21:19: Unsupported: class extends
21 | class Cls extends Base2;
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
ok(1);
1;

View File

@ -0,0 +1,42 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
typedef class Cls;
class Base0;
// No members to check that to_string handles this
endclass
class Base1 extends Base0;
int b1member;
endclass
class Base2 extends Base1;
int b2member;
endclass
class Cls extends Base2;
int imembera;
int imemberb;
endclass : Cls
module t (/*AUTOARG*/);
initial begin
Cls c;
c = new;
c.b1member = 10;
c.b2member = 30;
c.imembera = 100;
c.imemberb = 110;
$display("Display: set = \"%p\"", c); // '{all 4 members}
if (c.b1member != 10) $stop;
if (c.b2member != 30) $stop;
if (c.imembera != 100) $stop;
if (c.imemberb != 110) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_class_extends_bad.v:13:26: Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), and unsupported for interface classes.
13 | class Cls extends Base1, Base2;
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Base1;
endclass
class Base2;
endclass
class Cls extends Base1, Base2;
endclass
module t (/*AUTOARG*/);
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,40 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
package P;
typedef class ClsB;
class ClsA;
int imembera;
ClsB b;
endclass
class ClsB;
int imemberb;
ClsA a;
endclass
endpackage
module t (/*AUTOARG*/);
P::ClsA ca;
P::ClsB cb;
initial begin
// Alternate between two versions to make sure we don't
// constant propagate between them.
ca = new;
cb = new;
ca.b = new;
cb.a = new;
ca.imembera = 100;
ca.b.imemberb = 111;
cb.imemberb = 200;
cb.a.imembera = 202;
if (ca.imembera != 100) $stop;
if (ca.b.imemberb != 111) $stop;
if (cb.imemberb != 200) $stop;
if (cb.a.imembera != 202) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,7 @@
%Error: t/t_class_local.v:12:22: Unsupported: initial value on member
12 | local int m_loc = 2;
| ^
%Error: t/t_class_local.v:13:27: Unsupported: initial value on member
13 | protected int m_prot = B;
| ^
%Error: Exiting due to

23
test_regress/t/t_class_local.pl Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
ok(1);
1;

View File

@ -0,0 +1,27 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
class Cls;
typedef enum {A = 10, B = 20, C = 30} en_t;
local int m_loc = 2;
protected int m_prot = B;
endclass
initial begin
Cls c;
if (c.A != 10) $stop;
c = new;
if (c.m_loc != 2) $stop;
c.m_loc = 10;
if (c.m_loc != 10) $stop;
if (c.m_prot != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_class_member_bad.v:11:20: Unsupported: class extends
11 | class Cls2 extends Base1;
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,20 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Base1;
int memb1;
endclass
class Cls2 extends Base1;
int memb2;
endclass
module t (/*AUTOARG*/);
initial begin
Cls2 c;
c.memb3 = 3; // Not found
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,30 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
typedef class Cls;
class Cls;
int imembera;
function int get_methoda; return imembera; endfunction
task set_methoda(input int val); imembera = val; endtask
function void setv_methoda(input int val); imembera = val; endfunction
endclass : Cls
module t (/*AUTOARG*/);
initial begin
Cls c;
if (c != null) $stop;
c = new;
c.imembera = 10;
if (c.get_methoda() != 10) $stop;
c.set_methoda(20);
if (c.get_methoda() != 20) $stop;
c.setv_methoda(30);
if (c.get_methoda() != 30) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_class_method_bad.v:11:20: Unsupported: class extends
11 | class Cls2 extends Base1;
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,20 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Base1;
task meth1; endtask
endclass
class Cls2 extends Base1;
task meth2; endtask
endclass
module t (/*AUTOARG*/);
initial begin
Cls2 c;
c.meth3(); // Not found
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
class Cls;
int imembera;
int imemberb;
endclass : Cls
class Dead;
endclass
initial begin
Cls c;
if (c != null) $stop;
c = new;
c.imembera = 10;
c.imemberb = 20;
if (c.imembera != 10) $stop;
if (c.imemberb != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_class_name.v:12:4: Unsupported: 'static' class item
12 | static task static_name;
| ^~~~~~
%Error: Exiting due to

23
test_regress/t/t_class_name.pl Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
ok(1);
1;

View File

@ -0,0 +1,34 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
task unit_name;
$write("unit_name = '%m'\n");
endtask
class Cls;
static task static_name;
$write("static_name = '%m'\n");
endtask
task nonstatic_name;
$write("nonstatic_name = '%m'\n");
endtask
endclass : Cls
module t (/*AUTOARG*/);
initial begin
Cls c;
c = new;
$write("t = '%m'\n");
unit_name();
$write("Below results vary with simulator.\n");
// E.g. '$unit.\Cls::static_name '
// E.g. '$unit_x.Cls.static_name'
c.static_name();
c.nonstatic_name();
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,13 @@
%Error: t/t_class_new.v:9:13: Unsupported: new constructor
: ... In instance t
9 | function new();
| ^~~
%Error: t/t_class_new.v:16:13: Unsupported: new constructor
: ... In instance t
16 | function new(int i);
| ^~~
%Error: t/t_class_new.v:27:12: Unsupported: new with arguments
: ... In instance t
27 | c2 = new(2);
| ^~~
%Error: Exiting due to

23
test_regress/t/t_class_new.pl Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
ok(1);
1;

View File

@ -0,0 +1,33 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class ClsNoArg;
int imembera;
function new();
imembera = 5;
endfunction
endclass
class ClsArg;
int imembera;
function new(int i);
imembera = i + 1;
endfunction
endclass
module t (/*AUTOARG*/);
initial begin
ClsNoArg c1;
ClsArg c2;
c1 = new;
if (c1.imembera != 5) $stop;
c2 = new(2);
if (c2.imembera != 3) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,13 @@
%Error: t/t_class_new_bad.v:10:13: Unsupported: new constructor
: ... In instance t
10 | function new();
| ^~~
%Error: t/t_class_new_bad.v:17:13: Unsupported: new constructor
: ... In instance t
17 | function new(int i);
| ^~~
%Error: t/t_class_new_bad.v:26:12: Unsupported: new with arguments
: ... In instance t
26 | c1 = new(3);
| ^~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,30 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class ClsNoArg;
int imembera;
function new();
imembera = 5;
endfunction
endclass
class ClsArg;
int imembera;
function new(int i);
imembera = i + 1;
endfunction
endclass
module t (/*AUTOARG*/);
initial begin
ClsNoArg c1;
ClsArg c2;
c1 = new(3); // Bad, called with arg
c2 = new(); // Bad, called without arg
$stop;
end
endmodule

View File

@ -0,0 +1,2 @@
%Error: t/t_class_null_bad.v:15: Null pointer dereferenced
Aborting...

View File

@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,19 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Cls;
int imembera;
endclass : Cls
module t (/*AUTOARG*/);
Cls c;
initial begin
c = null; // Not really required as null is default
c.imembera = 10; // BAD IEEE 8.4
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,47 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
package pkga;
int pvar;
class MyClass;
int member;
function int getpvar(); return pvar; endfunction
endclass
endpackage
package pkgb;
int pvar;
class MyClass;
int member;
function int getpvar(); return pvar; endfunction
function int getavar(); return pkga::pvar; endfunction
endclass
endpackage
module t (/*AUTOARG*/);
initial begin
pkga::MyClass a;
pkgb::MyClass b;
pkga::pvar = 100;
pkgb::pvar = 200;
if (pkga::pvar != 100) $stop;
if (pkgb::pvar != 200) $stop;
a = new;
b = new;
a.member = 10;
b.member = 20;
if (a.member != 10) $stop;
if (b.member != 20) $stop;
if (a.getpvar() != 100) $stop;
if (b.getpvar() != 200) $stop;
if (b.getavar() != 100) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_class_param.v:20:11: Unsupported: Parameter classes
20 | Cls #(.P(4)) c4;
| ^
%Error: Exiting due to

23
test_regress/t/t_class_param.pl Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
ok(1);
1;

View File

@ -0,0 +1,40 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
class Cls #(parameter P = 12);
bit [P-1:0] member;
function bit [P-1:0] get_member;
return member;
endfunction
function int get_p;
return P;
endfunction
endclass
Cls c12;
Cls #(.P(4)) c4;
initial begin
c12 = new;
c4 = new;
if (c12.P != 12) $stop;
if (c4.P != 4) $stop;
if (c12.get_p() != 12) $stop;
if (c4.get_p() != 4) $stop;
// verilator lint_off WIDTH
c12.member = 32'haaaaaaaa;
c4.member = 32'haaaaaaaa;
// verilator lint_on WIDTH
if (c12.member != 12'haaa) $stop;
if (c4.member != 4'ha) $stop;
if (c12.get_member() != 12'haaa) $stop;
if (c4.get_member() != 4'ha) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,10 @@
%Error: t/t_class_static_order.v:23:4: Unsupported: 'static' class item
23 | static ClsZ z = new;
| ^~~~~~
%Error: t/t_class_static_order.v:34:4: Unsupported: 'static' class item
34 | static ClsA a = new;
| ^~~~~~
%Error: t/t_class_static_order.v:35:4: Unsupported: 'static' class item
35 | static ClsB b = new;
| ^~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
#execute(
# check_finished => 1,
# );
ok(1);
1;

View File

@ -0,0 +1,60 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class ClsZ;
function new();
$display("ClsZ::new");
endfunction
endclass
class ClsA;
function new();
$display("ClsA::new");
endfunction
function void access;
$display("ClsA::access");
endfunction
endclass
class ClsB;
static ClsZ z = new;
function new();
$display("ClsB::new");
endfunction
function void access;
$display("ClsB::access");
endfunction
endclass
class ClsC;
// Elaboration will call these
static ClsA a = new;
static ClsB b = new;
function new();
$display("ClsC::new");
endfunction
function void access;
$display("ClsC::access");
a = new;
a.access;
endfunction
endclass
module t (/*AUTOARG*/);
function void makec;
ClsC c;
$display("c = new;");
c = new;
$display("c.access;");
c.access;
endfunction
initial begin
$display("makec;");
makec;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -4,9 +4,6 @@
%Error: t/t_class_unsup_bad.v:8:1: Unsupported: virtual data type
8 | virtual vi_t vi2;
| ^~~~~~~
%Error: t/t_class_unsup_bad.v:13:1: Unsupported: classes
13 | class C #(parameter P=1);
| ^~~~~
%Error: t/t_class_unsup_bad.v:14:26: Unsupported: class parameters
14 | localparam LOCPAR = 10;
| ^
@ -14,15 +11,18 @@
25 | virtual function void func_virtual; endfunction
| ^~~~~~~
%Error: t/t_class_unsup_bad.v:26:4: Unsupported: pure virtual class method
26 | pure virtual function void func_pure_virtual; endfunction
26 | pure virtual function void func_pure_virtual;
| ^~~~
%Error: t/t_class_unsup_bad.v:26:50: syntax error, unexpected endfunction
26 | pure virtual function void func_pure_virtual; endfunction
| ^~~~~~~~~~~
%Error: t/t_class_unsup_bad.v:27:4: Unsupported: automatic class member qualifier
27 | automatic function void func_automatic; endfunction
| ^~~~~~~~~
%Error: t/t_class_unsup_bad.v:28:4: Unsupported: const class member qualifier
28 | const function void func_const; endfunction
| ^~~~~
%Error: t/t_class_unsup_bad.v:29:4: Unsupported: extern class method prototype
29 | extern task exttask;
| ^~~~~~
%Error: t/t_class_unsup_bad.v:32:1: Unsupported: virtual classes
32 | virtual class VC;
| ^~~~~~~
%Error: t/t_class_unsup_bad.v:32:9: Unsupported: classes
32 | virtual class VC;
| ^~~~~
%Error: Exiting due to

View File

@ -2,7 +2,7 @@
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2019 by Wilson Snyder. This program is free software; you
# Copyright 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.

View File

@ -23,7 +23,7 @@ class C #(parameter P=1);
task classtask; endtask
function int classfunc; endfunction
virtual function void func_virtual; endfunction
pure virtual function void func_pure_virtual; endfunction
pure virtual function void func_pure_virtual;
automatic function void func_automatic; endfunction
const function void func_const; endfunction
extern task exttask;

View File

@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1);
compile(
fails => ($Self->{vlt} || $Self->{vltmt}), # Unsupported bug1523
fails => $Self->{vlt_all}, # Unsupported bug1523
expect_filename => $Self->{golden_filename},
);

View File

@ -0,0 +1,2 @@
%Error: Unsupported: --savable with dynamic new
%Error: Exiting due to

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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
scenarios(vlt => 1);
compile(
v_flags2 => ["--savable"],
save_time => 500,
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

Some files were not shown because too many files have changed in this diff Show More