forked from github/verilator
Support enum.first/name and similar methods, bug848.
This commit is contained in:
parent
93f1d7643d
commit
c1593f856d
2
Changes
2
Changes
@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
** SystemPerl mode is deprecated and now untested.
|
||||
|
||||
*** Support enum.first/name and similar methods, bug848. [Jonathon Donaldson]
|
||||
|
||||
*** Add 'string' printing and comparisons, bug746, bug747, etc.
|
||||
|
||||
*** Inline C functions that are used only once, msg1525. [Jie Xu]
|
||||
|
@ -239,6 +239,13 @@ public:
|
||||
//
|
||||
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
|
||||
//
|
||||
ENUM_FIRST, // V3Width processes
|
||||
ENUM_LAST, // V3Width processes
|
||||
ENUM_NUM, // V3Width processes
|
||||
ENUM_NEXT, // V3Width processes
|
||||
ENUM_PREV, // V3Width processes
|
||||
ENUM_NAME, // V3Width processes
|
||||
//
|
||||
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
@ -259,6 +266,7 @@ public:
|
||||
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
|
||||
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
|
||||
"DT_PUBLIC",
|
||||
"ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME",
|
||||
"MEMBER_BASE",
|
||||
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
|
||||
|
@ -881,6 +881,32 @@ public:
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
};
|
||||
|
||||
class AstMethodSel : public AstNode {
|
||||
// A reference to a member task (or function)
|
||||
// We do not support generic member calls yet, so this is only enough to make built-in methods work
|
||||
private:
|
||||
string m_name; // Name of variable
|
||||
public:
|
||||
AstMethodSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp)
|
||||
: AstNode(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
AstMethodSel(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
|
||||
:AstNode(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(MethodSel, METHODSEL)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* pinsp() const { return op2p()->castNode(); } // op2 = Pin interconnection list
|
||||
void addPinsp(AstNode* nodep) { addOp2p(nodep); }
|
||||
};
|
||||
|
||||
class AstVar : public AstNode {
|
||||
// A variable (in/out/wire/reg/param) inside a module
|
||||
private:
|
||||
|
@ -1805,6 +1805,15 @@ private:
|
||||
// EnumItemRef may be under a dot. Should already be resolved.
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstMethodSel* nodep, AstNUser*) {
|
||||
// Created here so should already be resolved.
|
||||
DotStates lastStates = m_ds;
|
||||
{
|
||||
m_ds.init(m_curSymp);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
m_ds = lastStates;
|
||||
}
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
checkNoDot(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
@ -1823,6 +1832,14 @@ private:
|
||||
m_ds.m_dotp = NULL;
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
|
||||
nodep->dotted(m_ds.m_dotText); // Maybe ""
|
||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
|
||||
// Found a Var, everything following is method call. {scope}.{var}.HERE {method} ( ARGS )
|
||||
AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
|
||||
AstNode* argsp = NULL; if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
||||
AstNode* newp = new AstMethodSel(nodep->fileline(), varEtcp, VFlagChildDType(), nodep->name(), argsp);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
return;
|
||||
} else {
|
||||
checkNoDot(nodep);
|
||||
}
|
||||
|
@ -410,12 +410,16 @@ private:
|
||||
condp->deleteTree();
|
||||
}
|
||||
else if (!lvalue
|
||||
&& !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension
|
||||
&& !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension
|
||||
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
V3Number xnum (nodep->fileline(), nodep->width());
|
||||
xnum.setAllBitsX();
|
||||
if (nodep->isString()) {
|
||||
xnum = V3Number(V3Number::String(), nodep->fileline(), "");
|
||||
} else {
|
||||
xnum.setAllBitsX();
|
||||
}
|
||||
AstNode* newp = new AstCondBound (nodep->fileline(),
|
||||
condp,
|
||||
nodep,
|
||||
|
188
src/V3Width.cpp
188
src/V3Width.cpp
@ -1314,21 +1314,29 @@ private:
|
||||
if (debug()>=9) nodep->dumpTree("-ms-in-");
|
||||
nodep->iterateChildren(*this,WidthVP(SELF,BOTH).p());
|
||||
// Find the fromp dtype - should be a class
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp();
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
AstNodeClassDType* fromClassp = fromDtp->castNodeClassDType();
|
||||
AstMemberDType* memberp = NULL; // NULL=error below
|
||||
if (!fromClassp) {
|
||||
nodep->v3error("Member selection of non-struct/union object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
else {
|
||||
// No need to width-resolve the fromClassp, as it was done when we did the child
|
||||
memberp = fromClassp->findMember(nodep->name());
|
||||
if (AstNodeClassDType* adtypep = fromDtp->castNodeClassDType()) {
|
||||
// No need to width-resolve the class, as it was done when we did the child
|
||||
memberp = adtypep->findMember(nodep->name());
|
||||
if (!memberp) {
|
||||
nodep->v3error("Member '"<<nodep->prettyName()<<"' not found in structure");
|
||||
}
|
||||
}
|
||||
else if (fromDtp->castEnumDType()) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
// Convert this into a method call, and let that visitor figure out what to do next
|
||||
AstNode* newp = new AstMethodSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), NULL);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
newp->accept(*this,vup);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Member selection of non-struct/union object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
if (memberp) {
|
||||
if (m_attrp) { // Looking for the base of the attribute
|
||||
nodep->dtypep(memberp);
|
||||
@ -1350,6 +1358,96 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstMethodSel* nodep, AstNUser* vup) {
|
||||
UINFO(5," METHODSEL "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree("-ms-in-");
|
||||
// Should check types the method requires, but at present we don't do much
|
||||
nodep->fromp()->accept(*this,WidthVP(SELF,BOTH).p());
|
||||
for (AstArg* argp = nodep->pinsp()->castArg(); argp; argp = argp->nextp()->castArg()) {
|
||||
if (argp->exprp()) argp->exprp()->accept(*this,WidthVP(SELF,BOTH).p());
|
||||
}
|
||||
// Find the fromp dtype - should be a class
|
||||
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
if (AstEnumDType* adtypep = fromDtp->castEnumDType()) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
// Convert this into a method call, and let that visitor figure out what to do next
|
||||
if (adtypep) {}
|
||||
if (nodep->name() == "num"
|
||||
|| nodep->name() == "first"
|
||||
|| nodep->name() == "last") {
|
||||
// Constant value
|
||||
AstConst* newp = NULL;
|
||||
if (nodep->pinsp()) nodep->v3error("Arguments passed to enum.num method, but it does not take arguments");
|
||||
if (nodep->name() == "num") {
|
||||
int items = 0;
|
||||
for (AstNode* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()) ++items;
|
||||
newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items);
|
||||
} else if (nodep->name() == "first") {
|
||||
AstEnumItem* itemp = adtypep->itemsp();
|
||||
if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); // Spec doesn't say what to do
|
||||
else newp = itemp->valuep()->cloneTree(false)->castConst(); // A const
|
||||
} else if (nodep->name() == "last") {
|
||||
AstEnumItem* itemp = adtypep->itemsp();
|
||||
while (itemp && itemp->nextp()) itemp = itemp->nextp()->castEnumItem();
|
||||
if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); // Spec doesn't say what to do
|
||||
else newp = itemp->valuep()->cloneTree(false)->castConst(); // A const
|
||||
}
|
||||
if (!newp) nodep->v3fatalSrc("Enum method (perhaps enum item) not const");
|
||||
newp->fileline(nodep->fileline()); // Use method's filename/line number to be clearer; may have warning disables
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else if (nodep->name() == "name"
|
||||
|| nodep->name() == "next"
|
||||
|| nodep->name() == "prev") {
|
||||
AstAttrType attrType;
|
||||
if (nodep->name() == "name") attrType = AstAttrType::ENUM_NAME;
|
||||
else if (nodep->name() == "next") attrType = AstAttrType::ENUM_NEXT;
|
||||
else if (nodep->name() == "prev") attrType = AstAttrType::ENUM_PREV;
|
||||
else nodep->v3fatalSrc("Bad case");
|
||||
|
||||
if (nodep->pinsp() && nodep->name() == "name") {
|
||||
nodep->v3error("Arguments passed to enum.name method, but it does not take arguments");
|
||||
} else if (nodep->pinsp() && !(nodep->pinsp()->castArg()->exprp()->castConst()
|
||||
&& nodep->pinsp()->castArg()->exprp()->castConst()->toUInt()==1
|
||||
&& !nodep->pinsp()->nextp())) {
|
||||
nodep->v3error("Unsupported: Arguments passed to enum.next method");
|
||||
}
|
||||
// Need a runtime lookup table. Yuk.
|
||||
// Ideally we would have a fast algorithm when a number is
|
||||
// of small width and complete and so can use an array, and
|
||||
// a map for when the value is many bits and sparse.
|
||||
uint64_t max = 0;
|
||||
{
|
||||
AstEnumItem* itemp = adtypep->itemsp();
|
||||
while (itemp && itemp->nextp()) {
|
||||
itemp = itemp->nextp()->castEnumItem();
|
||||
AstConst* vconstp = itemp->valuep()->castConst();
|
||||
if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
|
||||
if (vconstp->toUQuad() >= max) max = vconstp->toUQuad();
|
||||
}
|
||||
if (itemp->width() > 64 || max >= 1024) {
|
||||
nodep->v3error("Unsupported; enum next/prev method on enum with > 10 bits");
|
||||
return;
|
||||
}
|
||||
}
|
||||
AstVar* varp = enumVarp(adtypep, attrType, max);
|
||||
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
|
||||
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, nodep->fromp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
} else {
|
||||
nodep->v3error("Unknown built-in enum method '"<<nodep->fromp()->prettyTypeName()<<"'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Unsupported: Member call on non-enum object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPattern* nodep, AstNUser* vup) {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
UINFO(9,"PATTERN "<<nodep<<endl);
|
||||
@ -3208,6 +3306,78 @@ private:
|
||||
m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
|
||||
return varp;
|
||||
}
|
||||
AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t maxdim) {
|
||||
// Return a variable table which has specified dimension properties for this variable
|
||||
TableMap::iterator pos = m_tableMap.find(make_pair(nodep,attrType));
|
||||
if (pos != m_tableMap.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
AstNodeDType* basep;
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
basep = nodep->findStringDType();
|
||||
} else {
|
||||
basep = nodep->findSigned32DType();
|
||||
}
|
||||
AstNodeArrayDType* vardtypep = new AstUnpackArrayDType(nodep->fileline(),
|
||||
basep,
|
||||
new AstRange(nodep->fileline(), maxdim, 0));
|
||||
AstInitArray* initp = new AstInitArray (nodep->fileline(), vardtypep, NULL);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__Venumtab_" + VString::downcase(attrType.ascii()) + cvtToStr(m_dtTables++),
|
||||
vardtypep);
|
||||
varp->isConst(true);
|
||||
varp->isStatic(true);
|
||||
varp->valuep(initp);
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
|
||||
|
||||
// Find valid values and populate
|
||||
if (!nodep->itemsp()) nodep->v3fatalSrc("enum without items");
|
||||
vector<AstNode*> values;
|
||||
values.reserve(maxdim);
|
||||
for (unsigned i=0; i<(maxdim+1); ++i) values[i] = NULL;
|
||||
{
|
||||
AstEnumItem* firstp = nodep->itemsp();
|
||||
AstEnumItem* prevp = firstp; // Prev must start with last item
|
||||
while (prevp->nextp()) prevp = prevp->nextp()->castEnumItem();
|
||||
for (AstEnumItem* itemp = firstp; itemp;) {
|
||||
AstEnumItem* nextp = itemp->nextp()->castEnumItem();
|
||||
AstConst* vconstp = itemp->valuep()->castConst();
|
||||
if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
|
||||
uint32_t i = vconstp->toUInt();
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
values[i] = new AstConst(nodep->fileline(), AstConst::String(), itemp->name());
|
||||
} else if (attrType == AstAttrType::ENUM_NEXT) {
|
||||
values[i] = (nextp ? nextp : firstp)->valuep()->cloneTree(false); // A const
|
||||
} else if (attrType == AstAttrType::ENUM_PREV) {
|
||||
values[i] = prevp->valuep()->cloneTree(false); // A const
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
prevp = itemp;
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
// Fill in all unspecified values and add to table
|
||||
for (unsigned i=0; i<(maxdim+1); ++i) {
|
||||
AstNode* valp = values[i];
|
||||
if (!valp) {
|
||||
if (attrType == AstAttrType::ENUM_NAME) {
|
||||
valp = new AstConst(nodep->fileline(), AstConst::String(), "");
|
||||
} else if (attrType == AstAttrType::ENUM_NEXT
|
||||
|| attrType == AstAttrType::ENUM_PREV) {
|
||||
valp = new AstConst(nodep->fileline(), V3Number(nodep->fileline(), nodep->width(), 0));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
}
|
||||
initp->addInitsp(valp);
|
||||
}
|
||||
varp->iterate(*this); // May have already done $unit so must do this var
|
||||
m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
|
||||
return varp;
|
||||
}
|
||||
|
||||
PatVecMap patVectorMap(AstPattern* nodep, const VNumRange& range) {
|
||||
PatVecMap patmap;
|
||||
|
@ -1,48 +1,10 @@
|
||||
// DESCRIPTION: Verilator: System Verilog test of enumerated type methods
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This code instantiates a module that uses a localparam with an enumerated
|
||||
// type.
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use, without
|
||||
// warranty.
|
||||
|
||||
// Contributed 2012 by M W Lund, Atmel Corporation and Jeremy Bennett, Embecosm.
|
||||
|
||||
|
||||
// **** Pin Identifiers ****
|
||||
typedef enum int
|
||||
{
|
||||
PINID_A0 = 32'd0, // MUST BE ZERO!
|
||||
// - Standard Ports -
|
||||
PINID_A1, PINID_A2, PINID_A3, PINID_A4, PINID_A5, PINID_A6, PINID_A7,
|
||||
PINID_B0, PINID_B1, PINID_B2, PINID_B3, PINID_B4, PINID_B5, PINID_B6, PINID_B7,
|
||||
PINID_C0, PINID_C1, PINID_C2, PINID_C3, PINID_C4, PINID_C5, PINID_C6, PINID_C7,
|
||||
PINID_D0, PINID_D1, PINID_D2, PINID_D3, PINID_D4, PINID_D5, PINID_D6, PINID_D7,
|
||||
PINID_E0, PINID_E1, PINID_E2, PINID_E3, PINID_E4, PINID_E5, PINID_E6, PINID_E7,
|
||||
PINID_F0, PINID_F1, PINID_F2, PINID_F3, PINID_F4, PINID_F5, PINID_F6, PINID_F7,
|
||||
PINID_G0, PINID_G1, PINID_G2, PINID_G3, PINID_G4, PINID_G5, PINID_G6, PINID_G7,
|
||||
PINID_H0, PINID_H1, PINID_H2, PINID_H3, PINID_H4, PINID_H5, PINID_H6, PINID_H7,
|
||||
// PINID_I0, PINID_I1, PINID_I2, PINID_I3, PINID_I4, PINID_I5, PINID_I6, PINID_I7,-> DO NOT USE!!!! I == 1
|
||||
PINID_J0, PINID_J1, PINID_J2, PINID_J3, PINID_J4, PINID_J5, PINID_J6, PINID_J7,
|
||||
PINID_K0, PINID_K1, PINID_K2, PINID_K3, PINID_K4, PINID_K5, PINID_K6, PINID_K7,
|
||||
PINID_L0, PINID_L1, PINID_L2, PINID_L3, PINID_L4, PINID_L5, PINID_L6, PINID_L7,
|
||||
PINID_M0, PINID_M1, PINID_M2, PINID_M3, PINID_M4, PINID_M5, PINID_M6, PINID_M7,
|
||||
PINID_N0, PINID_N1, PINID_N2, PINID_N3, PINID_N4, PINID_N5, PINID_N6, PINID_N7,
|
||||
// PINID_O0, PINID_O1, PINID_O2, PINID_O3, PINID_O4, PINID_O5, PINID_O6, PINID_O7,-> DO NOT USE!!!! O == 0
|
||||
PINID_P0, PINID_P1, PINID_P2, PINID_P3, PINID_P4, PINID_P5, PINID_P6, PINID_P7,
|
||||
PINID_Q0, PINID_Q1, PINID_Q2, PINID_Q3, PINID_Q4, PINID_Q5, PINID_Q6, PINID_Q7,
|
||||
PINID_R0, PINID_R1, PINID_R2, PINID_R3, PINID_R4, PINID_R5, PINID_R6, PINID_R7,
|
||||
// - AUX Port (Custom) -
|
||||
PINID_X0, PINID_X1, PINID_X2, PINID_X3, PINID_X4, PINID_X5, PINID_X6, PINID_X7,
|
||||
// - PDI Port -
|
||||
PINID_D2W_DAT, PINID_D2W_CLK,
|
||||
// - Power Pins -
|
||||
PINID_VDD0, PINID_VDD1, PINID_VDD2, PINID_VDD3,
|
||||
PINID_GND0, PINID_GND1, PINID_GND2, PINID_GND3,
|
||||
// - Maximum number of pins -
|
||||
PINID_MAX
|
||||
} t_pinid;
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2014 by Wilson Snyder.
|
||||
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
@ -50,26 +12,85 @@ module t (/*AUTOARG*/
|
||||
);
|
||||
input clk;
|
||||
|
||||
wire a = clk;
|
||||
wire b = 1'b0;
|
||||
reg c;
|
||||
|
||||
simple_test_1 simple_test_1_i (/*AUTOINST*/
|
||||
// Outputs
|
||||
.c (c),
|
||||
// Inputs
|
||||
.a (a),
|
||||
.b (b));
|
||||
typedef enum {
|
||||
E01 = 1,
|
||||
E03 = 3,
|
||||
E04 = 4
|
||||
} my_t;
|
||||
|
||||
// This is a compile time only test. Immediately finish
|
||||
always @(posedge clk) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
integer cyc=0;
|
||||
my_t e;
|
||||
|
||||
int arrayfits [e.num]; // Check can use as constant
|
||||
|
||||
string all;
|
||||
|
||||
// Check constification
|
||||
initial begin
|
||||
e = E03;
|
||||
`checkh(e.first, E01);
|
||||
`checkh(e.last, E04);
|
||||
`checkh(e.last(), E04);
|
||||
`checkh(e.next, E04);
|
||||
`checkh(e.next(), E04);
|
||||
`checkh(e.next(1), E04);
|
||||
//Unsup: `checkh(e.next(2), E01);
|
||||
`checkh(e.prev, E01);
|
||||
`checkh(e.prev(1), E01);
|
||||
//Unsup: `checkh(e.prev(2), E04);
|
||||
`checkh(e.num, 3);
|
||||
`checks(e.name, "E03");
|
||||
//
|
||||
all = "";
|
||||
for (my_t e = e.first; e != e.last; e = e.next) begin
|
||||
all = {all, e.name};
|
||||
end
|
||||
e = e.last;
|
||||
all = {all, e.name};
|
||||
`checks(all, "E01E03E04");
|
||||
end
|
||||
|
||||
// Check runtime
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
e <= E01;
|
||||
end
|
||||
else if (cyc==1) begin
|
||||
`checks(e.name, "E01");
|
||||
`checkh(e.next, E03);
|
||||
`checkh(e.next(1), E03);
|
||||
//Unsup: `checkh(e.next(2), E04);
|
||||
`checkh(e.prev, E04);
|
||||
`checkh(e.prev(1), E04);
|
||||
//Unsup: `checkh(e.prev(2), E03);
|
||||
e <= E03;
|
||||
end
|
||||
else if (cyc==2) begin
|
||||
`checks(e.name, "E03");
|
||||
`checkh(e.next, E04);
|
||||
`checkh(e.next(1), E04);
|
||||
//Unsup: `checkh(e.next(2), E01);
|
||||
`checkh(e.prev, E01);
|
||||
`checkh(e.prev(1), E01);
|
||||
//Unsup: `checkh(e.prev(2), E04);
|
||||
e <= E04;
|
||||
end
|
||||
else if (cyc==3) begin
|
||||
`checks(e.name, "E04");
|
||||
`checkh(e.next, E01);
|
||||
`checkh(e.next(1), E01);
|
||||
//Unsup: `checkh(e.next(2), E03);
|
||||
`checkh(e.prev, E03);
|
||||
`checkh(e.prev(1), E03);
|
||||
//Unsup: `checkh(e.prev(2), E01);
|
||||
e <= E01;
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
// **** Simple use of parameters for sizing an array ****
|
||||
module simple_test_1 (input a, b, output c);
|
||||
int myarray1 [PINID_MAX];
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user