mirror of
https://github.com/verilator/verilator.git
synced 2025-07-31 07:56:10 +00:00
Add simplistic class support with many restrictions, see manual, #377.
This commit is contained in:
parent
f6048cc9c1
commit
6eadb8e771
2
Changes
2
Changes
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -167,6 +167,7 @@ RAW_OBJS = \
|
||||
V3Cast.o \
|
||||
V3Cdc.o \
|
||||
V3Changed.o \
|
||||
V3Class.o \
|
||||
V3Clean.o \
|
||||
V3Clock.o \
|
||||
V3Combine.o \
|
||||
|
12
src/V3Ast.h
12
src/V3Ast.h
@ -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; }
|
||||
};
|
||||
|
@ -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]";
|
||||
|
101
src/V3AstNodes.h
101
src/V3AstNodes.h
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
src/V3CUse.cpp
110
src/V3CUse.cpp
@ -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
|
||||
|
||||
|
@ -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
143
src/V3Class.cpp
Normal 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
33
src/V3Class.h
Normal 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
|
@ -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()
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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:"); }
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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());
|
||||
|
110
src/V3Width.cpp
110
src/V3Width.cpp
@ -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()
|
||||
|
@ -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--------------
|
||||
|
@ -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
|
||||
|
4
test_regress/t/t_class1.out
Normal file
4
test_regress/t/t_class1.out
Normal 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
22
test_regress/t/t_class1.pl
Executable 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
29
test_regress/t/t_class1.v
Normal 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
|
10
test_regress/t/t_class2.out
Normal file
10
test_regress/t/t_class2.out
Normal 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
25
test_regress/t/t_class2.pl
Executable 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
40
test_regress/t/t_class2.v
Normal 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
|
4
test_regress/t/t_class_class.out
Normal file
4
test_regress/t/t_class_class.out
Normal 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
19
test_regress/t/t_class_class.pl
Executable 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;
|
34
test_regress/t/t_class_class.v
Normal file
34
test_regress/t/t_class_class.v
Normal 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
21
test_regress/t/t_class_copy.pl
Executable 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;
|
37
test_regress/t/t_class_copy.v
Normal file
37
test_regress/t/t_class_copy.v
Normal 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
|
5
test_regress/t/t_class_copy_bad.out
Normal file
5
test_regress/t/t_class_copy_bad.out
Normal 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
|
19
test_regress/t/t_class_copy_bad.pl
Executable file
19
test_regress/t/t_class_copy_bad.pl
Executable 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;
|
21
test_regress/t/t_class_copy_bad.v
Normal file
21
test_regress/t/t_class_copy_bad.v
Normal 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
25
test_regress/t/t_class_dead.pl
Executable 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;
|
30
test_regress/t/t_class_dead.v
Normal file
30
test_regress/t/t_class_dead.v
Normal 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
21
test_regress/t/t_class_enum.pl
Executable 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;
|
19
test_regress/t/t_class_enum.v
Normal file
19
test_regress/t/t_class_enum.v
Normal 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
|
10
test_regress/t/t_class_extends.out
Normal file
10
test_regress/t/t_class_extends.out
Normal 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
|
23
test_regress/t/t_class_extends.pl
Executable file
23
test_regress/t/t_class_extends.pl
Executable 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;
|
42
test_regress/t/t_class_extends.v
Normal file
42
test_regress/t/t_class_extends.v
Normal 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
|
4
test_regress/t/t_class_extends_bad.out
Normal file
4
test_regress/t/t_class_extends_bad.out
Normal 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
|
19
test_regress/t/t_class_extends_bad.pl
Executable file
19
test_regress/t/t_class_extends_bad.pl
Executable 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;
|
17
test_regress/t/t_class_extends_bad.v
Normal file
17
test_regress/t/t_class_extends_bad.v
Normal 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
|
21
test_regress/t/t_class_forward.pl
Executable file
21
test_regress/t/t_class_forward.pl
Executable 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;
|
40
test_regress/t/t_class_forward.v
Normal file
40
test_regress/t/t_class_forward.v
Normal 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
|
7
test_regress/t/t_class_local.out
Normal file
7
test_regress/t/t_class_local.out
Normal 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
23
test_regress/t/t_class_local.pl
Executable 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;
|
27
test_regress/t/t_class_local.v
Normal file
27
test_regress/t/t_class_local.v
Normal 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
|
4
test_regress/t/t_class_member_bad.out
Normal file
4
test_regress/t/t_class_member_bad.out
Normal 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
|
19
test_regress/t/t_class_member_bad.pl
Executable file
19
test_regress/t/t_class_member_bad.pl
Executable 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;
|
20
test_regress/t/t_class_member_bad.v
Normal file
20
test_regress/t/t_class_member_bad.v
Normal 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
|
21
test_regress/t/t_class_method.pl
Executable file
21
test_regress/t/t_class_method.pl
Executable 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;
|
30
test_regress/t/t_class_method.v
Normal file
30
test_regress/t/t_class_method.v
Normal 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
|
4
test_regress/t/t_class_method_bad.out
Normal file
4
test_regress/t/t_class_method_bad.out
Normal 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
|
19
test_regress/t/t_class_method_bad.pl
Executable file
19
test_regress/t/t_class_method_bad.pl
Executable 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;
|
20
test_regress/t/t_class_method_bad.v
Normal file
20
test_regress/t/t_class_method_bad.v
Normal 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
|
21
test_regress/t/t_class_module.pl
Executable file
21
test_regress/t/t_class_module.pl
Executable 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;
|
28
test_regress/t/t_class_module.v
Normal file
28
test_regress/t/t_class_module.v
Normal 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
|
4
test_regress/t/t_class_name.out
Normal file
4
test_regress/t/t_class_name.out
Normal 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
23
test_regress/t/t_class_name.pl
Executable 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;
|
34
test_regress/t/t_class_name.v
Normal file
34
test_regress/t/t_class_name.v
Normal 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
|
13
test_regress/t/t_class_new.out
Normal file
13
test_regress/t/t_class_new.out
Normal 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
23
test_regress/t/t_class_new.pl
Executable 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;
|
33
test_regress/t/t_class_new.v
Normal file
33
test_regress/t/t_class_new.v
Normal 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
|
13
test_regress/t/t_class_new_bad.out
Normal file
13
test_regress/t/t_class_new_bad.out
Normal 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
|
19
test_regress/t/t_class_new_bad.pl
Executable file
19
test_regress/t/t_class_new_bad.pl
Executable 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;
|
30
test_regress/t/t_class_new_bad.v
Normal file
30
test_regress/t/t_class_new_bad.v
Normal 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
|
2
test_regress/t/t_class_null_bad.out
Normal file
2
test_regress/t/t_class_null_bad.out
Normal file
@ -0,0 +1,2 @@
|
||||
%Error: t/t_class_null_bad.v:15: Null pointer dereferenced
|
||||
Aborting...
|
22
test_regress/t/t_class_null_bad.pl
Executable file
22
test_regress/t/t_class_null_bad.pl
Executable 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;
|
19
test_regress/t/t_class_null_bad.v
Normal file
19
test_regress/t/t_class_null_bad.v
Normal 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
|
21
test_regress/t/t_class_package.pl
Executable file
21
test_regress/t/t_class_package.pl
Executable 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;
|
47
test_regress/t/t_class_package.v
Normal file
47
test_regress/t/t_class_package.v
Normal 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
|
4
test_regress/t/t_class_param.out
Normal file
4
test_regress/t/t_class_param.out
Normal 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
23
test_regress/t/t_class_param.pl
Executable 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;
|
40
test_regress/t/t_class_param.v
Normal file
40
test_regress/t/t_class_param.v
Normal 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
|
10
test_regress/t/t_class_static_order.out
Normal file
10
test_regress/t/t_class_static_order.out
Normal 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
|
23
test_regress/t/t_class_static_order.pl
Executable file
23
test_regress/t/t_class_static_order.pl
Executable 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;
|
60
test_regress/t/t_class_static_order.v
Normal file
60
test_regress/t/t_class_static_order.v
Normal 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
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
);
|
||||
|
||||
|
2
test_regress/t/t_savable_class_bad.out
Normal file
2
test_regress/t/t_savable_class_bad.out
Normal file
@ -0,0 +1,2 @@
|
||||
%Error: Unsupported: --savable with dynamic new
|
||||
%Error: Exiting due to
|
21
test_regress/t/t_savable_class_bad.pl
Executable file
21
test_regress/t/t_savable_class_bad.pl
Executable 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
Loading…
Reference in New Issue
Block a user