Support little endian bit vectors ("reg [0:2] x;").
This commit is contained in:
parent
350028553b
commit
39444d83c5
2
Changes
2
Changes
|
|
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
* Verilator 3.71****
|
||||
|
||||
** Support little endian bit vectors ("reg [0:2] x;").
|
||||
|
||||
**** Fix writing to out-of-bounds arrays writing element 0.
|
||||
|
||||
**** Fix core dump with SystemVerilog var declarations under unnamed begins.
|
||||
|
|
|
|||
|
|
@ -667,8 +667,8 @@ Disable the specified warning message.
|
|||
|
||||
Disable all lint related warning messages. This is equivalent to
|
||||
"-Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASEWITHX
|
||||
-Wno-CMPCONST -Wno-IMPLICIT -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED
|
||||
-Wno-VARHIDDEN -Wno-WIDTH".
|
||||
-Wno-CMPCONST -Wno-IMPLICIT -Wno-LITENDIAN -Wno-UNDRIVEN -Wno-UNSIGNED
|
||||
-Wno-UNUSED -Wno-VARHIDDEN -Wno-WIDTH".
|
||||
|
||||
It is strongly recommended you cleanup your code rather than using this
|
||||
option, it is only intended to be use when running test-cases of code
|
||||
|
|
@ -1954,6 +1954,16 @@ Verilator cannot schedule these variables correctly.
|
|||
Ignoring this warning may make Verilator simulations differ from other
|
||||
simulators.
|
||||
|
||||
=item LITENDIAN
|
||||
|
||||
Warns that a vector is declared with little endian bit numbering
|
||||
(i.e. [0:7]). Big endian bit numbering is now the overwhelming standard,
|
||||
and little numbering is now thus often due to simple oversight instead of
|
||||
intent.
|
||||
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
|
||||
=item MULTIDRIVEN
|
||||
|
||||
Warns that the specified signal comes from multiple always blocks. This is
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ RAW_OBJS = \
|
|||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3Width.o \
|
||||
V3WidthSel.o \
|
||||
|
||||
# Non-concatable
|
||||
OBJS += \
|
||||
|
|
|
|||
|
|
@ -170,9 +170,8 @@ class AstAttrType {
|
|||
public:
|
||||
enum en {
|
||||
BITS, // V3Const converts to constant
|
||||
RANGE_LSB, // V3Const converts to constant
|
||||
ARRAY_LSB, // V3Const converts to constant
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked
|
||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
||||
|
|
@ -182,7 +181,7 @@ public:
|
|||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"BITS", "RANGE_LSB", "ARRAY_LSB",
|
||||
"BITS", "VAR_BASE",
|
||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
||||
"VAR_ISOLATE_ASSIGNMENTS"
|
||||
};
|
||||
|
|
@ -942,11 +941,14 @@ struct AstNodePreSel : public AstNode {
|
|||
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
|
||||
ASTNODE_BASE_FUNCS(NodePreSel)
|
||||
AstNode* lhsp() const { return op1p()->castNode(); }
|
||||
AstNode* fromp() const { return lhsp(); }
|
||||
AstNode* rhsp() const { return op2p()->castNode(); }
|
||||
AstNode* thsp() const { return op3p()->castNode(); }
|
||||
AstAttrOf* attrp() const { return op4p()->castAttrOf(); }
|
||||
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
||||
void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); }
|
||||
// METHODS
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
|
|
|
|||
|
|
@ -141,6 +141,14 @@ AstRange* AstVar::arrayp(int dimension) const {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int AstVar::arrayDimensions() const {
|
||||
int entries=0;
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
entries++;
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
uint32_t AstVar::arrayElements() const {
|
||||
uint32_t entries=1;
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
|
|
@ -149,6 +157,37 @@ uint32_t AstVar::arrayElements() const {
|
|||
return entries;
|
||||
}
|
||||
|
||||
// Special operators
|
||||
int AstArraySel::dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
|
||||
// Only called after V3Param; so only ArraySel's need to be recursed
|
||||
int dim = 0;
|
||||
while (nodep) {
|
||||
if (nodep->castNodeSel()) { dim++; nodep=nodep->castNodeSel()->fromp(); continue; }
|
||||
if (nodep->castNodePreSel()) { dim++; nodep=nodep->castNodePreSel()->fromp(); continue; }
|
||||
break;
|
||||
}
|
||||
return dim;
|
||||
}
|
||||
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
|
||||
// Else AstArraySel etc; search for the base
|
||||
while (nodep) {
|
||||
if (nodep->castArraySel()) { nodep=nodep->castArraySel()->fromp(); continue; }
|
||||
else if (nodep->castSel()) { nodep=nodep->castSel()->fromp(); continue; }
|
||||
// AstNodeSelPre stashes the associated variable under a ATTROF so it isn't constified
|
||||
else if (nodep->castAttrOf()) { nodep=nodep->castAttrOf()->fromp(); continue; }
|
||||
else if (nodep->castNodePreSel()) {
|
||||
if (nodep->castNodePreSel()->attrp()) {
|
||||
nodep=nodep->castNodePreSel()->attrp();
|
||||
} else {
|
||||
nodep=nodep->castNodePreSel()->lhsp();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
|
||||
bool AstScope::broken() const {
|
||||
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|
||||
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|
||||
|
|
@ -303,6 +342,10 @@ void AstPin::dump(ostream& str) {
|
|||
else { str<<" ->UNLINKED"; }
|
||||
if (svImplicit()) str<<" [.SV]";
|
||||
}
|
||||
void AstRange::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (littleEndian()) str<<" [LITTLE]";
|
||||
}
|
||||
void AstVarXRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (lvalue()) str<<" [LV] => ";
|
||||
|
|
|
|||
|
|
@ -76,20 +76,30 @@ public:
|
|||
|
||||
struct AstRange : public AstNode {
|
||||
// Range specification, for use under variables and cells
|
||||
private:
|
||||
bool m_littleEndian:1; // Bit vector is little endian
|
||||
public:
|
||||
AstRange(FileLine* fl, AstNode* msbp, AstNode* lsbp)
|
||||
:AstNode(fl) {
|
||||
m_littleEndian = false;
|
||||
setOp2p(msbp); setOp3p(lsbp); }
|
||||
AstRange(FileLine* fl, int msb, int lsb)
|
||||
:AstNode(fl) {
|
||||
m_littleEndian = false;
|
||||
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
|
||||
width(msb-lsb+1,msb-lsb+1);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Range, RANGE)
|
||||
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
|
||||
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
|
||||
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
|
||||
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
|
||||
AstNode* msbEndianedp() const { return littleEndian()?lsbp():msbp(); } // How to show a declaration
|
||||
AstNode* lsbEndianedp() const { return littleEndian()?msbp():lsbp(); }
|
||||
int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int elementsConst() const { return msbConst()-lsbConst()+1; }
|
||||
int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; }
|
||||
bool littleEndian() const { return m_littleEndian; }
|
||||
void littleEndian(bool flag) { m_littleEndian=flag; }
|
||||
virtual void dump(ostream& str);
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
|
|
@ -120,15 +130,8 @@ struct AstArraySel : public AstNodeSel {
|
|||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
// Special operators
|
||||
static int dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
|
||||
int dim = 0;
|
||||
while (nodep && nodep->castArraySel()) { dim++; nodep=nodep->castArraySel()->fromp(); }
|
||||
return dim;
|
||||
}
|
||||
static AstNode* baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
|
||||
while (nodep && nodep->castArraySel()) { nodep=nodep->castArraySel()->fromp(); }
|
||||
return nodep;
|
||||
}
|
||||
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
|
||||
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
|
||||
};
|
||||
|
||||
struct AstWordSel : public AstNodeSel {
|
||||
|
|
@ -153,6 +156,8 @@ struct AstSelExtract : public AstNodePreSel {
|
|||
AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp)
|
||||
: AstNodePreSel(fl, fromp, msbp, lsbp) {}
|
||||
ASTNODE_NODE_FUNCS(SelExtract, SELEXTRACT)
|
||||
AstNode* msbp() const { return rhsp(); }
|
||||
AstNode* lsbp() const { return thsp(); }
|
||||
};
|
||||
|
||||
struct AstSelBit : public AstNodePreSel {
|
||||
|
|
@ -163,6 +168,7 @@ struct AstSelBit : public AstNodePreSel {
|
|||
width(1,1);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(SelBit, SELBIT)
|
||||
AstNode* bitp() const { return rhsp(); }
|
||||
};
|
||||
|
||||
struct AstSelPlus : public AstNodePreSel {
|
||||
|
|
@ -171,6 +177,8 @@ struct AstSelPlus : public AstNodePreSel {
|
|||
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||
ASTNODE_NODE_FUNCS(SelPlus, SELPLUS)
|
||||
AstNode* bitp() const { return rhsp(); }
|
||||
AstNode* widthp() const { return thsp(); }
|
||||
};
|
||||
|
||||
struct AstSelMinus : public AstNodePreSel {
|
||||
|
|
@ -179,6 +187,8 @@ struct AstSelMinus : public AstNodePreSel {
|
|||
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||
ASTNODE_NODE_FUNCS(SelMinus, SELMINUS)
|
||||
AstNode* bitp() const { return rhsp(); }
|
||||
AstNode* widthp() const { return thsp(); }
|
||||
};
|
||||
|
||||
struct AstSel : public AstNodeTriop {
|
||||
|
|
@ -358,7 +368,11 @@ public:
|
|||
int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,...
|
||||
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
||||
int lsb() const { if (!rangep()) return 0; return rangep()->lsbConst(); }
|
||||
int msbEndianed() const { if (!rangep()) return 0; return littleEndian()?rangep()->lsbConst():rangep()->msbConst(); }
|
||||
int lsbEndianed() const { if (!rangep()) return 0; return littleEndian()?rangep()->msbConst():rangep()->lsbConst(); }
|
||||
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
|
||||
bool littleEndian() const { return (rangep() && rangep()->littleEndian()); }
|
||||
int arrayDimensions() const;
|
||||
uint32_t arrayElements() const; // 1, or total multiplication of all dimensions
|
||||
virtual string verilogKwd() const;
|
||||
void propagateAttrFrom(AstVar* fromp) {
|
||||
|
|
@ -1620,7 +1634,7 @@ public:
|
|||
widthSignedFrom(varp);
|
||||
m_code = 0;
|
||||
m_codeInc = varp->arrayElements() * varp->widthWords();
|
||||
m_lsb = varp->lsb(); m_msb = varp->msb();
|
||||
m_lsb = varp->lsbEndianed(); m_msb = varp->msbEndianed();
|
||||
m_arrayLsb = varp->arrayp(0) ? varp->arrayp(0)->lsbConst() : 0;
|
||||
m_arrayMsb = varp->arrayp(0) ? varp->arrayp(0)->msbConst() : 0;
|
||||
}
|
||||
|
|
@ -1634,8 +1648,8 @@ public:
|
|||
uint32_t code() const { return m_code; }
|
||||
void code(uint32_t code) { m_code=code; }
|
||||
uint32_t codeInc() const { return m_codeInc; }
|
||||
int msb() const { return m_msb; }
|
||||
int lsb() const { return m_lsb; }
|
||||
int msbEndianed() const { return m_msb; } // Note msb maybe < lsb if little endian
|
||||
int lsbEndianed() const { return m_lsb; }
|
||||
uint32_t arrayMsb() const { return m_arrayMsb; }
|
||||
uint32_t arrayLsb() const { return m_arrayLsb; }
|
||||
uint32_t arrayWidth() const { if (!arrayMsb()) return 0; return arrayMsb()-arrayLsb()+1; }
|
||||
|
|
@ -1717,15 +1731,14 @@ struct AstAttrOf : public AstNode {
|
|||
private:
|
||||
// Return a value of a attribute, for example a LSB or array LSB of a signal
|
||||
AstAttrType m_attrType; // What sort of extraction
|
||||
int m_dimension; // Dimension number (0 is leftmost), for ARRAY_LSB extractions
|
||||
public:
|
||||
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL, int dimension=0)
|
||||
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL)
|
||||
: AstNode(fl) {
|
||||
setNOp1p(fromp); m_attrType = attrtype; m_dimension = dimension; }
|
||||
setNOp1p(fromp);
|
||||
m_attrType = attrtype; }
|
||||
ASTNODE_NODE_FUNCS(AttrOf, ATTROF)
|
||||
AstNode* fromp() const { return op1p(); }
|
||||
AstAttrType attrType() const { return m_attrType; }
|
||||
int dimension() const { return m_dimension; }
|
||||
virtual void dump(ostream& str=cout);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1053,7 +1053,7 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||
bool did=false;
|
||||
if (!m_cpp && nodep->varp()->hasSimpleInit()) {
|
||||
if (!m_cpp && nodep->varp()->hasSimpleInit() && !nodep->backp()->castAttrOf()) {
|
||||
//if (debug()) nodep->varp()->initp()->dumpTree(cout," visitvaref: ");
|
||||
nodep->varp()->initp()->iterateAndNext(*this);
|
||||
if (operandConst(nodep->varp()->initp())
|
||||
|
|
@ -1079,23 +1079,7 @@ private:
|
|||
V3Number num (nodep->fileline(), 32, nodep->fromp()->widthMin());
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
} else {
|
||||
if (!nodep->fromp()->castNodeVarRef()) nodep->v3fatalSrc("Not linked");
|
||||
AstVar* varp = nodep->fromp()->castNodeVarRef()->varp();
|
||||
if (!varp) nodep->v3fatalSrc("Not linked");
|
||||
if (nodep->attrType()==AstAttrType::RANGE_LSB) {
|
||||
if (!varp->rangep()) nodep->v3fatalSrc("RANGE_LSB on vec w/o range\n");
|
||||
if (operandConst(varp->rangep()->lsbp())) {
|
||||
V3Number num (nodep->fileline(), 32, varp->lsb());
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
}
|
||||
} else if (nodep->attrType()==AstAttrType::ARRAY_LSB) {
|
||||
AstRange* arrayp=varp->arrayp(nodep->dimension());
|
||||
if (!arrayp) nodep->v3fatalSrc("ARRAY_LSB on vec w/o range or right # dimensions\n");
|
||||
if (operandConst(arrayp->lsbp())) {
|
||||
V3Number num (nodep->fileline(), 32, arrayp->lsbConst());
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
}
|
||||
} else nodep->v3fatalSrc("Missing ATTR type case\n");
|
||||
nodep->v3fatalSrc("Missing ATTR type case");
|
||||
}
|
||||
}
|
||||
bool onlySenItemInSenTree(AstNodeSenItem* nodep) {
|
||||
|
|
@ -1471,6 +1455,10 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// These are converted by V3Param. Don't constify as we don't want the from() VARREF to disappear, if any
|
||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
||||
|
||||
//-----
|
||||
// Below lines are magic expressions processed by astgen
|
||||
// "AstNODETYPE { # bracket not paren
|
||||
|
|
@ -1746,7 +1734,9 @@ public:
|
|||
|
||||
AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
|
||||
//if (debug()>0) nodep->dumpTree(cout," forceConPRE : ");
|
||||
nodep = V3Width::widthParamsEditIfNeed(nodep); // Make sure we've sized everything first
|
||||
// Resize even if the node already has a width, because burried in the treee we may
|
||||
// have a node we just created with signing, etc, that isn't sized yet.
|
||||
nodep = V3Width::widthParamsEdit(nodep); // Make sure we've sized everything first
|
||||
ConstVisitor visitor (true,false,false,false);
|
||||
if (AstVar* varp=nodep->castVar()) {
|
||||
// If a var wants to be constified, it's really a param, and
|
||||
|
|
|
|||
|
|
@ -1839,7 +1839,7 @@ class EmitCTrace : EmitCStmts {
|
|||
puts("vcdp->declArray");
|
||||
} else if (nodep->isQuad()) {
|
||||
puts("vcdp->declQuad ");
|
||||
} else if (nodep->msb() || nodep->lsb()) {
|
||||
} else if (nodep->msbEndianed() || nodep->lsbEndianed()) {
|
||||
puts("vcdp->declBus ");
|
||||
} else {
|
||||
puts("vcdp->declBit ");
|
||||
|
|
@ -1853,8 +1853,8 @@ class EmitCTrace : EmitCStmts {
|
|||
} else {
|
||||
puts(",-1");
|
||||
}
|
||||
if (nodep->msb() || nodep->lsb()) {
|
||||
puts(","+cvtToStr(nodep->msb())+","+cvtToStr(nodep->lsb()));
|
||||
if (nodep->msbEndianed() || nodep->lsbEndianed()) {
|
||||
puts(","+cvtToStr(nodep->msbEndianed())+","+cvtToStr(nodep->lsbEndianed()));
|
||||
}
|
||||
puts(");");
|
||||
}
|
||||
|
|
@ -1868,7 +1868,7 @@ class EmitCTrace : EmitCStmts {
|
|||
puts("vcdp->"+full+"Array");
|
||||
} else if (nodep->isQuad()) {
|
||||
puts("vcdp->"+full+"Quad ");
|
||||
} else if (nodep->declp()->msb() || nodep->declp()->lsb()) {
|
||||
} else if (nodep->declp()->msbEndianed() || nodep->declp()->lsbEndianed()) {
|
||||
puts("vcdp->"+full+"Bus ");
|
||||
} else {
|
||||
puts("vcdp->"+full+"Bit ");
|
||||
|
|
@ -1877,7 +1877,7 @@ class EmitCTrace : EmitCStmts {
|
|||
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
|
||||
puts(",");
|
||||
emitTraceValue(nodep, arrayindex);
|
||||
if (nodep->declp()->msb() || nodep->declp()->lsb()) {
|
||||
if (nodep->declp()->msbEndianed() || nodep->declp()->lsbEndianed()) {
|
||||
puts(","+cvtToStr(nodep->declp()->widthMin()));
|
||||
}
|
||||
puts(");\n");
|
||||
|
|
|
|||
|
|
@ -368,8 +368,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
virtual void visit(AstRange* nodep, AstNUser*) {
|
||||
puts("[");
|
||||
nodep->msbp()->iterateAndNext(*this); puts(":");
|
||||
nodep->lsbp()->iterateAndNext(*this); puts("]");
|
||||
nodep->msbEndianedp()->iterateAndNext(*this); puts(":");
|
||||
nodep->lsbEndianedp()->iterateAndNext(*this); puts("]");
|
||||
}
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
nodep->fromp()->iterateAndNext(*this); puts("[");
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public:
|
|||
IMPERFECTSCH, // Imperfect schedule (disabled by default)
|
||||
IMPLICIT, // Implicit wire
|
||||
IMPURE, // Impure function not being inlined
|
||||
LITENDIAN, // Little bit endian vector
|
||||
MULTIDRIVEN, // Driven from multiple blocks
|
||||
REDEFMACRO, // Redefining existing define macro
|
||||
UNDRIVEN, // No drivers
|
||||
|
|
@ -96,6 +97,7 @@ public:
|
|||
"BLKANDNBLK",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CMPCONST",
|
||||
"COMBDLY", "STMTDLY", "SYMRSVDWORD", "GENCLK", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
|
||||
"LITENDIAN",
|
||||
"MULTIDRIVEN", "REDEFMACRO",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
||||
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
|
||||
|
|
@ -118,6 +120,7 @@ public:
|
|||
|| m_e==CASEWITHX || m_e==CASEX
|
||||
|| m_e==CMPCONST
|
||||
|| m_e==IMPLICIT
|
||||
|| m_e==LITENDIAN
|
||||
|| m_e==UNDRIVEN || m_e==UNSIGNED
|
||||
|| m_e==UNUSED || m_e==VARHIDDEN
|
||||
|| m_e==WIDTH); }
|
||||
|
|
|
|||
|
|
@ -160,6 +160,11 @@ private:
|
|||
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
||||
did=1;
|
||||
}
|
||||
if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
|
||||
AstNode* fromp = selp->lhsp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
||||
did=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nodep->sensp()->castNodeVarRef()) {
|
||||
|
|
@ -171,151 +176,19 @@ private:
|
|||
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
|
||||
}
|
||||
|
||||
void iterateSelTriop(AstNodePreSel* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
AstNode* newSubAttrOf(AstNode* underp, AstNode* fromp, AstAttrType attrType) {
|
||||
// Account for a variable's LSB in bit selections
|
||||
// Replace underp with a SUB(underp, ATTROF(varp, attrType))
|
||||
int dimension=0;
|
||||
while (fromp && !fromp->castNodeVarRef() && (fromp->castSel() || fromp->castArraySel())) {
|
||||
if (fromp->castSel()) fromp = fromp->castSel()->fromp();
|
||||
else fromp = fromp->castArraySel()->fromp();
|
||||
dimension++;
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
if (!nodep->attrp()) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Constification may change the fromp() to a constant, which will loose the
|
||||
// variable we're extracting from (to determine MSB/LSB/endianness/etc.)
|
||||
// So we replicate it in another node
|
||||
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||
AstNodeVarRef* varrefp = basefromp->castNodeVarRef(); // Maybe varxref - so need to clone
|
||||
if (!varrefp) nodep->v3fatalSrc("Illegal bit select; no signal being extracted from");
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||
varrefp->cloneTree(false)));
|
||||
}
|
||||
AstNodeVarRef* varrefp = fromp->castNodeVarRef();
|
||||
if (!varrefp) fromp->v3fatalSrc("Bit/array selection of non-variable");
|
||||
if (!varrefp->varp()) varrefp->v3fatalSrc("Signal not linked");
|
||||
AstRange* vararrayp = varrefp->varp()->arrayp(dimension);
|
||||
AstRange* varrangep = varrefp->varp()->rangep();
|
||||
if ((attrType==AstAttrType::ARRAY_LSB
|
||||
// SUB #'s Not needed because LSB==0? (1D only, else we'll constify it later)
|
||||
? (vararrayp && !vararrayp->lsbp()->isZero())
|
||||
: (varrangep && !varrangep->lsbp()->isZero()))) {
|
||||
AstNode* newrefp;
|
||||
if (varrefp->castVarXRef()) {
|
||||
newrefp = new AstVarXRef(underp->fileline(),
|
||||
varrefp->varp(), varrefp->castVarXRef()->dotted(), false);
|
||||
} else {
|
||||
newrefp = new AstVarRef (underp->fileline(),
|
||||
varrefp->varp(), false);
|
||||
}
|
||||
AstNode* newp = new AstSub (underp->fileline(),
|
||||
underp,
|
||||
new AstAttrOf(underp->fileline(),
|
||||
attrType, newrefp, dimension));
|
||||
return newp;
|
||||
} else {
|
||||
return underp;
|
||||
}
|
||||
}
|
||||
|
||||
void selCheckDimension(AstSel* nodep) {
|
||||
// Perform error checks on the node
|
||||
AstNode* fromp = nodep->lhsp();
|
||||
AstNode* basefromp = AstArraySel::baseFromp(fromp);
|
||||
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
|
||||
AstVar* varp = varrefp ? varrefp->varp() : NULL;
|
||||
if (fromp->castSel()
|
||||
|| (varp && !varp->rangep() && !varp->isParam())) {
|
||||
nodep->v3error("Illegal bit select; variable already selected, or bad dimension");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||
// Couldn't tell until link time if [#] references a bit or an array
|
||||
iterateSelTriop(nodep);
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* basefromp = AstArraySel::baseFromp(fromp);
|
||||
int dimension = AstArraySel::dimension(fromp);
|
||||
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
|
||||
if (varrefp
|
||||
&& varrefp->varp()
|
||||
&& varrefp->varp()->arrayp(dimension)) {
|
||||
// SELBIT(array, index) -> ARRAYSEL(array, index)
|
||||
AstNode* newp = new AstArraySel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
newSubAttrOf(bitp, fromp, AstAttrType::ARRAY_LSB));
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else {
|
||||
// SELBIT(range, index) -> SEL(array, index, 1)
|
||||
V3Number one (nodep->fileline(),32,1); one.width(32,false); // Unsized so width from user
|
||||
AstSel* newp = new AstSel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
newSubAttrOf(bitp, fromp, AstAttrType::RANGE_LSB),
|
||||
new AstConst (nodep->fileline(),one));
|
||||
selCheckDimension(newp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelExtract* nodep, AstNUser*) {
|
||||
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
|
||||
iterateSelTriop(nodep);
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
|
||||
AstNode* widthp;
|
||||
if (msbp->castConst() && lsbp->castConst()) {
|
||||
// Quite common, save V3Const some effort
|
||||
V3Number widnum (msbp->fileline(),32,msbp->castConst()->toSInt() +1-lsbp->castConst()->toSInt());
|
||||
widnum.width(32,false); // Unsized so width from user
|
||||
widthp = new AstConst (msbp->fileline(), widnum);
|
||||
pushDeletep(msbp);
|
||||
} else {
|
||||
V3Number one (nodep->fileline(),32,1); one.width(32,false); // Unsized so width from user
|
||||
widthp = new AstSub (lsbp->fileline(),
|
||||
new AstAdd(msbp->fileline(),
|
||||
new AstConst(msbp->fileline(),one),
|
||||
msbp),
|
||||
lsbp->cloneTree(true));
|
||||
}
|
||||
AstSel* newp = new AstSel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
newSubAttrOf(lsbp, fromp, AstAttrType::RANGE_LSB),
|
||||
widthp);
|
||||
selCheckDimension(newp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstSelPlus* nodep, AstNUser*) {
|
||||
// SELPLUS -> SEL
|
||||
iterateSelTriop(nodep);
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* lsbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* widthp = nodep->thsp()->unlinkFrBack();
|
||||
AstSel* newp = new AstSel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
newSubAttrOf(lsbp, fromp, AstAttrType::RANGE_LSB),
|
||||
widthp);
|
||||
selCheckDimension(newp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstSelMinus* nodep, AstNUser*) {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
|
||||
iterateSelTriop(nodep);
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* widthp = nodep->thsp()->unlinkFrBack();
|
||||
V3Number one (msbp->fileline(),32,1); one.width(32,false); // Unsized so width from user
|
||||
AstSel* newp = new AstSel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
newSubAttrOf(new AstSub (msbp->fileline(),
|
||||
msbp,
|
||||
new AstSub (msbp->fileline(),
|
||||
widthp->cloneTree(true),
|
||||
new AstConst (msbp->fileline(), one))),
|
||||
fromp, AstAttrType::RANGE_LSB),
|
||||
widthp);
|
||||
selCheckDimension(newp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ private:
|
|||
// NODE STATE
|
||||
// AstModule::user4() // bool True if parameters numbered
|
||||
// AstVar::user4() // int Global parameter number (for naming new module)
|
||||
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
|
||||
AstUser4InUse m_inuser4;
|
||||
// User1/2/3 used by constant function simulations
|
||||
|
||||
// STATE
|
||||
typedef std::map<AstVar*,AstVar*> VarCloneMap;
|
||||
|
|
@ -93,7 +95,7 @@ private:
|
|||
}
|
||||
}
|
||||
string paramSmallName(AstModule* modp, AstVar* varp) {
|
||||
if (!varp->user4()) {
|
||||
if (varp->user4()<=1) {
|
||||
makeSmallNames(modp);
|
||||
}
|
||||
int index = varp->user4()/256;
|
||||
|
|
@ -129,11 +131,19 @@ private:
|
|||
|
||||
// Make sure all parameters are constantified
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
if (nodep->isParam()) {
|
||||
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||
if (!nodep->user4()) {
|
||||
nodep->user4(1); // Mark done - Note values >1 used for letter numbering
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->isParam()) {
|
||||
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure varrefs cause vars to constify before things above
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->varp()) nodep->varp()->iterate(*this);
|
||||
}
|
||||
|
||||
// Generate Statements
|
||||
virtual void visit(AstGenerate* nodep, AstNUser*) {
|
||||
|
|
@ -151,6 +161,7 @@ private:
|
|||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstGenIf* nodep, AstNUser*) {
|
||||
nodep->condp()->iterateAndNext(*this);
|
||||
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
||||
V3Const::constifyParamsEdit(nodep->condp()); // condp may change
|
||||
if (AstConst* constp = nodep->condp()->castConst()) {
|
||||
|
|
@ -173,10 +184,12 @@ private:
|
|||
// We parse a very limited form of FOR, so we don't need to do a full
|
||||
// simulation to unroll the loop
|
||||
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
||||
// Note V3Unroll will replace some AstVarRef's to the loop variable with constants
|
||||
V3Unroll::unrollGen(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstGenCase* nodep, AstNUser*) {
|
||||
AstNode* keepp = NULL;
|
||||
nodep->exprp()->iterateAndNext(*this);
|
||||
V3Case::caseLint(nodep);
|
||||
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
||||
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
|
||||
|
|
@ -185,6 +198,7 @@ private:
|
|||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
for (AstNode* ep = itemp->condsp(); ep; ) {
|
||||
AstNode* nextp = ep->nextp(); //May edit list
|
||||
ep->iterateAndNext(*this);
|
||||
V3Const::constifyParamsEdit(ep); ep=NULL; // ep may change
|
||||
ep = nextp;
|
||||
}
|
||||
|
|
@ -240,6 +254,7 @@ public:
|
|||
|
||||
void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
|
||||
// Cell: Check for parameters in the instantiation.
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
|
||||
if (nodep->paramsp()) {
|
||||
UINFO(4,"De-parameterize: "<<nodep<<endl);
|
||||
|
|
|
|||
|
|
@ -503,7 +503,7 @@ private:
|
|||
UINFO(5," FUNCREF "<<nodep<<endl);
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
AstFunc* funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||
V3Width::widthParamsEditIfNeed(funcp); funcp=NULL; // Make sure we've sized the function
|
||||
if (m_params) { V3Width::widthParamsEdit(funcp); } funcp=NULL; // Make sure we've sized the function
|
||||
funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||
// Apply function call values to function
|
||||
// Note we'd need a stack if we allowed recursive functions!
|
||||
|
|
|
|||
|
|
@ -388,7 +388,8 @@ private:
|
|||
if (m_varModeReplace
|
||||
&& nodep->varp() == m_forVarp
|
||||
&& nodep->varScopep() == m_forVscp
|
||||
&& !nodep->lvalue()) {
|
||||
&& !nodep->lvalue()
|
||||
&& !nodep->backp()->castAttrOf()) { // Most likely under a select
|
||||
AstNode* newconstp = m_varValuep->cloneTree(false);
|
||||
nodep->replaceWith(newconstp);
|
||||
pushDeletep(nodep);
|
||||
|
|
|
|||
133
src/V3Width.cpp
133
src/V3Width.cpp
|
|
@ -249,39 +249,20 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstRange* nodep, AstNUser* vup) {
|
||||
// If there's an edit, then processes the edit'ee (can't just rely on iterateChildren because sometimes we for(...) here ourself
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
V3Const::constifyParamsEdit(nodep->msbp()); // msbp may change
|
||||
V3Const::constifyParamsEdit(nodep->lsbp()); // lsbp may change
|
||||
AstConst* msbConstp = nodep->msbp()->castConst();
|
||||
AstConst* lsbConstp = nodep->lsbp()->castConst();
|
||||
if (!msbConstp || !lsbConstp) {
|
||||
if (!msbConstp) nodep->v3error("MSB of bit range isn't a constant");
|
||||
if (!lsbConstp) nodep->v3error("LSB of bit range isn't a constant");
|
||||
nodep->width(1,1); return;
|
||||
}
|
||||
int msb = msbConstp->toSInt();
|
||||
int lsb = lsbConstp->toSInt();
|
||||
if (msb > (1<<28)) nodep->v3error("MSB of bit range is huge; vector of over 1billion bits: 0x"<<hex<<msb);
|
||||
if (msb<lsb) {
|
||||
// If it's a array, ok to have either ordering, we'll just correct
|
||||
// So, see if we're sitting under a variable's arrayp.
|
||||
AstNode* huntbackp = nodep;
|
||||
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
|
||||
if (huntbackp->backp()->castVar()
|
||||
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
|
||||
} else {
|
||||
nodep->v3error("Unsupported: MSB < LSB of bit range: "<<msb<<"<"<<lsb);
|
||||
}
|
||||
// Correct it.
|
||||
msbConstp->swapWith(lsbConstp);
|
||||
int x=msb; msb=lsb; lsb=x;
|
||||
}
|
||||
int width = msb-lsb+1;
|
||||
int width = nodep->elementsConst();
|
||||
if (width > (1<<28)) nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x"<<hex<<width);
|
||||
nodep->width(width,width);
|
||||
if (nodep->littleEndian()) {
|
||||
nodep->v3warn(LITENDIAN,"Little bit endian vector: MSB < LSB of bit range: "<<nodep->lsbConst()<<":"<<nodep->msbConst());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSel* nodep, AstNUser* vup) {
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
|
|
@ -383,6 +364,54 @@ private:
|
|||
widthCheck(nodep,"Extract Range",nodep->bitp(),selwidth,selwidth,true);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelBit* nodep, AstNUser* vup) {
|
||||
// Just a quick check as after V3Param these nodes instead are AstSel's
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
nodep->v3fatalSrc("AstSelBit should disappear after widthSel");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); // from
|
||||
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); // bit
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSelExtract* nodep, AstNUser* vup) {
|
||||
// Just a quick check as after V3Param these nodes instead are AstSel's
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
nodep->v3fatalSrc("AstSelExtract should disappear after widthSel");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelPlus* nodep, AstNUser* vup) {
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
nodep->v3fatalSrc("AstSelPlus should disappear after widthSel");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->bitp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
if (AstConst* constp = nodep->widthp()->castConst()) {
|
||||
int width = constp->toSInt();
|
||||
nodep->width(width,width);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSelMinus* nodep, AstNUser* vup) {
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
nodep->v3fatalSrc("AstSelMinus should disappear after widthSel");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->bitp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
if (AstConst* constp = nodep->widthp()->castConst()) {
|
||||
int width = constp->toSInt();
|
||||
nodep->width(width,width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstExtend* nodep, AstNUser* vup) {
|
||||
// Only created by this process, so we know width from here down it is correct.
|
||||
}
|
||||
|
|
@ -433,8 +462,8 @@ private:
|
|||
int selwidth = V3Number::log2b(nodep->lhsp()->width())+1;
|
||||
nodep->width(selwidth,selwidth);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->width(32,1); // Approximation, unsized 32
|
||||
}
|
||||
|
|
@ -526,8 +555,9 @@ private:
|
|||
AstNodeCase* lastCasep = m_casep;
|
||||
m_casep = nodep;
|
||||
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
for (AstCaseItem* nextp, *itemp = nodep->itemsp(); itemp; itemp=nextp) {
|
||||
nextp = itemp->nextp()->castCaseItem(); // Prelim may cause the node to get replaced
|
||||
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p()); itemp=NULL;
|
||||
}
|
||||
int width = nodep->exprp()->width();
|
||||
int mwidth = nodep->exprp()->widthMin();
|
||||
|
|
@ -552,8 +582,11 @@ private:
|
|||
// Need to look across multiple case values for one set of statements
|
||||
int width = nodep->condsp()->width();
|
||||
int mwidth = nodep->condsp()->widthMin();
|
||||
for (AstNode* nextp, *condp = nodep->condsp(); condp; condp=nextp) {
|
||||
nextp = condp->nextp(); // Prelim may cause the node to get replaced
|
||||
condp->iterate(*this,vup); condp=NULL;
|
||||
}
|
||||
for (AstNode* condp = nodep->condsp(); condp; condp=condp->nextp()) {
|
||||
condp->iterate(*this,vup);
|
||||
width = max(width,condp->width());
|
||||
mwidth = max(mwidth,condp->widthMin());
|
||||
if (vup->c()->final()) {
|
||||
|
|
@ -804,19 +837,25 @@ private:
|
|||
m_taskDepth--;
|
||||
}
|
||||
// And do the arguments to the task/function too
|
||||
AstNode* pinp = nodep->pinsp();
|
||||
AstNode* stmt_nextp; // List may change, so need to keep pointer
|
||||
for (AstNode* stmtp = nodep->taskp()->stmtsp(); stmtp; stmtp=stmt_nextp) {
|
||||
stmt_nextp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO()
|
||||
&& pinp!=NULL) { // Else argument error we'll find later
|
||||
AstNode* pin_nextp = pinp->nextp(); // List may change, so remember nextp
|
||||
int width = portp->width();
|
||||
int ewidth = portp->widthMin();
|
||||
pinp->accept(*this,WidthVP(width,ewidth,BOTH).p());
|
||||
widthCheck(nodep,"Function Argument",pinp,width,ewidth);
|
||||
pinp = pin_nextp;
|
||||
for (int accept_mode=1; accept_mode>=0; accept_mode--) { // Avoid duplicate code; just do inner stuff twice
|
||||
AstNode* pinp = nodep->pinsp();
|
||||
for (AstNode* stmt_nextp, *stmtp = nodep->taskp()->stmtsp(); stmtp; stmtp=stmt_nextp) {
|
||||
stmt_nextp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO()
|
||||
&& pinp!=NULL) { // Else argument error we'll find later
|
||||
AstNode* pin_nextp = pinp->nextp(); // List may change, so remember nextp
|
||||
if (accept_mode) {
|
||||
// Prelim may cause the node to get replaced; we've lost our
|
||||
// pointer, so need to iterate separately later
|
||||
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
|
||||
} else {
|
||||
// Do PRELIM again, because above accept may have exited early due to node replacement
|
||||
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
|
||||
widthCheck(nodep,"Function Argument",pinp,portp->width(),portp->widthMin());
|
||||
}
|
||||
pinp = pin_nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1193,6 +1232,10 @@ private:
|
|||
nodep->width(nodep->width(),nodep->width());
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
// This check could go anywhere after V3Param
|
||||
nodep->v3fatalSrc("Presels should have been removed before this point");
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
WidthCommitVisitor(AstNetlist* nodep) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ public:
|
|||
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
|
||||
// Final step... Mark all widths as equal
|
||||
static void widthCommit(AstNetlist* nodep);
|
||||
|
||||
// For use only in WidthVisitor
|
||||
// Replace AstSelBit, etc with AstSel/AstArraySel
|
||||
// Returns replacement node if nodep was deleted, or null if none.
|
||||
static AstNode* widthSelNoIterEdit(AstNode* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -0,0 +1,345 @@
|
|||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Expression width calculations
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3WidthSel's Transformations:
|
||||
// Top down traversal:
|
||||
// Replace SELPLUS/SELMINUS with SEL
|
||||
// Replace SELEXTRACT with SEL
|
||||
// Replace SELBIT with SEL or ARRAYSEL
|
||||
//
|
||||
// This code was once in V3LinkResolve, but little endian bit vectors won't
|
||||
// work that early. It was considered for V3Width and V3Param, but is
|
||||
// fairly ugly both places as the nodes change in too strongly
|
||||
// interconnected ways.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Const.h"
|
||||
|
||||
//######################################################################
|
||||
// Width state, as a visitor of each AstNode
|
||||
|
||||
class WidthSelVisitor : public AstNVisitor {
|
||||
private:
|
||||
// IMPORTANT
|
||||
//**** This is not a normal visitor, in that all iteration is instead
|
||||
// done by the caller (V3Width). This avoids duplicating much of the
|
||||
// complicated GenCase/GenFor/Cell/Function call logic that all depends
|
||||
// on if widthing top-down or just for parameters.
|
||||
#define iterateChildren DO_NOT_iterateChildern_IN_V3WidthSel
|
||||
//
|
||||
// NODE STATE
|
||||
// isBelowSeled() used insead of userp, as we're out of
|
||||
// non-conflicting users, and having a persistent variable means this
|
||||
// code can be skipped during most later stage constification calls.
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
void checkConstantOrReplace(AstNode* nodep, const string& message) {
|
||||
// Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
|
||||
if (!nodep->castConst()) {
|
||||
nodep->v3error(message);
|
||||
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void selCheckDimension(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
|
||||
// Perform error checks on the node
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: ");
|
||||
int dimensions = varp->arrayDimensions();
|
||||
if (dimension < dimensions) {
|
||||
if (rangedSelect) {
|
||||
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
|
||||
}
|
||||
} else if (dimension > dimensions) { // Too many indexes provided
|
||||
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
|
||||
} else if (dimension == dimensions) { // Right number, but...
|
||||
if (!varp->rangep()) {
|
||||
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
|
||||
// Return lhs-rhs, but if rhs is negative use an add, so we won't
|
||||
// have to deal with signed math and related 32bit sign extension problems
|
||||
if (rhs == 0) {
|
||||
return lhsp;
|
||||
} else if (rhs > 0) {
|
||||
// We must make sure sub gets sign of original value
|
||||
AstNode* newp = new AstSub(lhsp->fileline(), lhsp,
|
||||
new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs));
|
||||
newp->signedFrom(lhsp);
|
||||
return newp;
|
||||
} else { // rhs < 0;
|
||||
AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
|
||||
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
|
||||
newp->signedFrom(lhsp);
|
||||
return newp;
|
||||
}
|
||||
}
|
||||
AstNode* newSubNeg(vlsint32_t lhs, AstNode* rhsp) {
|
||||
// Return lhs-rhs
|
||||
// We must make sure sub gets sign of original value
|
||||
AstNode* newp = new AstSub(rhsp->fileline(),
|
||||
new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs),
|
||||
rhsp);
|
||||
newp->signedFrom(rhsp); // Important as AstSub default is lhs's sign
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstVar* varFromBasefrom(AstNode* basefromp) {
|
||||
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
|
||||
if (!varrefp) basefromp->v3fatalSrc("Bit/array selection of non-variable");
|
||||
AstVar* varp = varrefp->varp(); if (!varp) varrefp->v3fatalSrc("Signal not linked");
|
||||
return varp;
|
||||
}
|
||||
|
||||
AstNode* newSubLsbOf(AstNode* underp, AstNode* basefromp) {
|
||||
// Account for a variable's LSB in bit selections
|
||||
// Will likely become SUB(underp, lsb_of_signal)
|
||||
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
|
||||
if (!varp->rangep()) {
|
||||
// vector without range is ok, for example a INTEGER x; y = x[21:0];
|
||||
return underp;
|
||||
} else {
|
||||
if (!varp->rangep()->msbp()->castConst()
|
||||
|| !varp->rangep()->lsbp()->castConst())
|
||||
varp->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(varp)
|
||||
if (varp->littleEndian()) {
|
||||
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
|
||||
AstNode* newp = newSubNeg(varp->msb(), underp);
|
||||
return newp;
|
||||
} else {
|
||||
// reg [3:1] needs a SUB(under,1)
|
||||
AstNode* newp = newSubNeg(underp, varp->lsb());
|
||||
return newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
|
||||
|
||||
virtual void visit(AstRange* nodep, AstNUser*) {
|
||||
// Convert all range values to constants
|
||||
UINFO(6,"RANGE "<<nodep<<endl);
|
||||
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
|
||||
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
|
||||
checkConstantOrReplace(nodep->msbp(), "MSB of bit range isn't a constant");
|
||||
checkConstantOrReplace(nodep->lsbp(), "LSB of bit range isn't a constant");
|
||||
int msb = nodep->msbConst();
|
||||
int lsb = nodep->lsbConst();
|
||||
if (msb<lsb) {
|
||||
// If it's an array, ok to have either ordering, we'll just correct
|
||||
// So, see if we're sitting under a variable's arrayp.
|
||||
AstNode* huntbackp = nodep;
|
||||
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
|
||||
if (huntbackp->backp()->castVar()
|
||||
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
|
||||
} else {
|
||||
// Little endian bits are legal, just remember to swap
|
||||
// Warning is in V3Width to avoid false warnings when in "off" generate if's
|
||||
nodep->littleEndian(!nodep->littleEndian());
|
||||
}
|
||||
// Internally we'll always have msb() be the greater number
|
||||
// We only need to correct when doing [] AstSel extraction,
|
||||
// and when tracing the vector.
|
||||
nodep->msbp()->swapWith(nodep->lsbp());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||
UINFO(6,"SELBIT "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->backp()->dumpTree(cout,"-vsbin(-1): ");
|
||||
// lhsp/rhsp do not need to be constant
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
|
||||
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
|
||||
selCheckDimension(nodep, basefromp, dimension, false);
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-vsbmd: ");
|
||||
if (varp->arrayp(dimension)) {
|
||||
// SELBIT(array, index) -> ARRAYSEL(array, index)
|
||||
AstRange* arrayp = varp->arrayp(dimension); // NULL checked above
|
||||
AstNode* subp = bitp;
|
||||
if (!arrayp->lsbp()->isZero() || arrayp->msbConst()<0) {
|
||||
subp = newSubNeg (subp, arrayp->lsbConst());
|
||||
}
|
||||
AstArraySel* newp = new AstArraySel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
subp);
|
||||
UINFO(6," newd"<<dimension<<" "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else {
|
||||
// SELBIT(range, index) -> SEL(array, index, 1)
|
||||
AstSel* newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(bitp, basefromp),
|
||||
// Unsized so width from user
|
||||
new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
|
||||
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelExtract* nodep, AstNUser*) {
|
||||
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
|
||||
UINFO(6,"SELEXTRACT "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX0: ");
|
||||
// Below 2 lines may change nodep->widthp()
|
||||
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
|
||||
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
|
||||
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX3: ");
|
||||
checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
|
||||
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
vlsint32_t msb = msbp->castConst()->toSInt();
|
||||
vlsint32_t lsb = lsbp->castConst()->toSInt();
|
||||
selCheckDimension(nodep, basefromp, dimension, msb!=lsb);
|
||||
if (varp->rangep() && varp->rangep()->littleEndian()) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
}
|
||||
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
|
||||
msb +1-lsb);
|
||||
AstSel* newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(lsbp, basefromp),
|
||||
widthp);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(msbp); msbp=NULL;
|
||||
}
|
||||
|
||||
void replaceSelPlusMinus(AstNodePreSel* nodep) {
|
||||
UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
|
||||
// Below 2 lines may change nodep->widthp()
|
||||
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
|
||||
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
|
||||
// Now replace it with a AstSel
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
|
||||
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* widthp = nodep->thsp()->unlinkFrBack();
|
||||
int width = widthp->castConst()->toSInt();
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
|
||||
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
|
||||
selCheckDimension(nodep, basefromp, dimension, width!=1);
|
||||
AstSel* newp = NULL;
|
||||
if (nodep->castSelPlus()) {
|
||||
if (varp->rangep() && varp->rangep()->littleEndian()) {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg((varp->msb()-width+1), rhsp),
|
||||
widthp);
|
||||
} else {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(rhsp, basefromp),
|
||||
widthp);
|
||||
}
|
||||
} else if (nodep->castSelMinus()) {
|
||||
if (varp->rangep() && varp->rangep()->littleEndian()) {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg(varp->msb(), rhsp),
|
||||
widthp);
|
||||
} else {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg(rhsp, varp->lsb()+(width-1)),
|
||||
widthp);
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad Case");
|
||||
}
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstSelPlus* nodep, AstNUser*) {
|
||||
replaceSelPlusMinus(nodep);
|
||||
}
|
||||
virtual void visit(AstSelMinus* nodep, AstNUser*) {
|
||||
replaceSelPlusMinus(nodep);
|
||||
}
|
||||
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// See notes above; we never iterate
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
WidthSelVisitor() {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
return nodep->acceptSubtreeReturnEdits(*this);
|
||||
}
|
||||
virtual ~WidthSelVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Width class functions
|
||||
|
||||
AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) {
|
||||
WidthSelVisitor visitor;
|
||||
nodep = visitor.mainAcceptEdit(nodep);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
#undef iterateChildren
|
||||
|
|
@ -11,11 +11,14 @@ compile (
|
|||
fails=>$Self->{v3},
|
||||
nc=>0, # Need to get it not to give the prompt
|
||||
expect=>
|
||||
'%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
|
||||
%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
|
||||
%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
|
||||
%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
|
||||
%Error: Exiting due to.*',
|
||||
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dimn
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim1
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim0nv
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dim0nv
|
||||
.*%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
|
|
|||
|
|
@ -4,15 +4,19 @@
|
|||
// without warranty, 2005 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
reg dimn;
|
||||
reg [1:0] dim0;
|
||||
reg [1:0] dim1 [1:0];
|
||||
reg [1:0] dim2 [1:0][1:0];
|
||||
reg dim0nv[1:0];
|
||||
|
||||
initial begin
|
||||
dimn[1:0] = 0; // Bad: Not ranged
|
||||
dim0[1][1] = 0; // Bad: Not arrayed
|
||||
dim1[1][1][1] = 0; // Bad: Not arrayed to right depth
|
||||
dim2[1][1][1] = 0; // OK
|
||||
dim2[0 +: 1][1] = 0; // Bad: Range on non-bits
|
||||
dim2[1 : 0][1] = 0; // Bad: Range on non-bits
|
||||
dim2[1][1:0] = 0; // Bad: Bitsel too soon
|
||||
dim0nv[1:0] = 0; // Bad: Not vectored
|
||||
dim0nv[1][1] = 0; // Bad: Not arrayed to right depth
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
compile (
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_select_bad_msb.v:\d+: Unsupported: MSB < LSB of bit range: 0<22
|
||||
%Error: t/t_select_bad_msb.v:\d+: Unsupported: MSB < LSB of bit extract: 1<4
|
||||
'%Warning-LITENDIAN: t/t_select_bad_msb.v:\d+: Little bit endian vector: MSB < LSB of bit range: 0:22
|
||||
.*
|
||||
%Error: Exiting due to.*',
|
||||
) if $Self->{v3};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
reg [63:0] crc;
|
||||
reg [63:0] sum;
|
||||
|
||||
// verilator lint_off LITENDIAN
|
||||
wire [10:41] sel2 = crc[31:0];
|
||||
wire [10:100] sel3 = {crc[26:0],crc};
|
||||
|
||||
wire out20 = sel2[{1'b0,crc[3:0]} + 11];
|
||||
wire [3:0] out21 = sel2[13 : 16];
|
||||
wire [3:0] out22 = sel2[{1'b0,crc[3:0]} + 20 +: 4];
|
||||
wire [3:0] out23 = sel2[{1'b0,crc[3:0]} + 20 -: 4];
|
||||
|
||||
wire out30 = sel3[{2'b0,crc[3:0]} + 11];
|
||||
wire [3:0] out31 = sel3[13 : 16];
|
||||
wire [3:0] out32 = sel3[crc[5:0] + 20 +: 4];
|
||||
wire [3:0] out33 = sel3[crc[5:0] + 20 -: 4];
|
||||
|
||||
// Aggregate outputs into a single result vector
|
||||
wire [63:0] result = {38'h0, out20, out21, out22, out23, out30, out31, out32, out33};
|
||||
|
||||
reg [19:50] sel1;
|
||||
initial begin
|
||||
// Path clearing
|
||||
// 122333445
|
||||
// 826048260
|
||||
sel1 = 32'h12345678;
|
||||
if (sel1 != 32'h12345678) $stop;
|
||||
if (sel1[47 : 50] != 4'h8) $stop;
|
||||
if (sel1[31 : 34] != 4'h4) $stop;
|
||||
if (sel1[27 +: 4] != 4'h3) $stop; //==[27:30], in memory as [23:20]
|
||||
if (sel1[26 -: 4] != 4'h2) $stop; //==[23:26], in memory as [27:24]
|
||||
end
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] sels=%x,%x,%x,%x %x,%x,%x,%x\n",$time, out20,out21,out22,out23, out30,out31,out32,out33);
|
||||
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
crc <= 64'h5aef0c8d_d70a4497;
|
||||
end
|
||||
else if (cyc<10) begin
|
||||
sum <= 64'h0;
|
||||
end
|
||||
else if (cyc<90) begin
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
|
||||
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
||||
`define EXPECTED_SUM 64'h28bf65439eb12c00
|
||||
if (sum !== `EXPECTED_SUM) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -9,6 +9,7 @@ module t (
|
|||
);
|
||||
|
||||
neg neg (.clk(CLK));
|
||||
little little (.clk(CLK));
|
||||
glbl glbl ();
|
||||
|
||||
initial RESET = 1'b1;
|
||||
|
|
@ -43,5 +44,21 @@ module neg (
|
|||
i48 <= ~i48;
|
||||
i128 <= ~i128;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module little (
|
||||
input clk
|
||||
);
|
||||
|
||||
// verilator lint_off LITENDIAN
|
||||
reg [0:7] i8; initial i8 = '0;
|
||||
reg [1:49] i48; initial i48 = '0;
|
||||
reg [63:190] i128; initial i128 = '0;
|
||||
// verilator lint_on LITENDIAN
|
||||
|
||||
always @ (posedge clk) begin
|
||||
i8 <= ~i8;
|
||||
i48 <= ~i48;
|
||||
i128 <= ~i128;
|
||||
end
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -1,19 +1,25 @@
|
|||
$version Generated by SpTraceVcd $end
|
||||
$date Thu Sep 18 07:54:41 2008
|
||||
$date Sat Sep 26 15:04:50 2009
|
||||
$end
|
||||
$timescale 1ns $end
|
||||
|
||||
$scope module TOP $end
|
||||
$var wire 1 , CLK $end
|
||||
$var wire 1 - RESET $end
|
||||
$var wire 1 3 CLK $end
|
||||
$var wire 1 4 RESET $end
|
||||
$scope module v $end
|
||||
$var wire 1 , CLK $end
|
||||
$var wire 1 3 CLK $end
|
||||
$var wire 1 # RESET $end
|
||||
$scope module glbl $end
|
||||
$var wire 1 + GSR $end
|
||||
$var wire 1 2 GSR $end
|
||||
$upscope $end
|
||||
$scope module little $end
|
||||
$var wire 1 3 clk $end
|
||||
$var wire 128 . i128 [63:190] $end
|
||||
$var wire 49 , i48 [1:49] $end
|
||||
$var wire 8 + i8 [0:7] $end
|
||||
$upscope $end
|
||||
$scope module neg $end
|
||||
$var wire 1 , clk $end
|
||||
$var wire 1 3 clk $end
|
||||
$var wire 128 ' i128 [63:-64] $end
|
||||
$var wire 48 % i48 [-1:-48] $end
|
||||
$var wire 8 $ i8 [0:-7] $end
|
||||
|
|
@ -28,44 +34,56 @@ $enddefinitions $end
|
|||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
1+
|
||||
1-
|
||||
0,
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
12
|
||||
14
|
||||
03
|
||||
#1
|
||||
#2
|
||||
#3
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
1,
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
13
|
||||
#4
|
||||
#5
|
||||
#6
|
||||
0,
|
||||
03
|
||||
#7
|
||||
0+
|
||||
02
|
||||
#8
|
||||
#9
|
||||
0#
|
||||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
0-
|
||||
1,
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
04
|
||||
13
|
||||
#10
|
||||
#11
|
||||
#12
|
||||
0,
|
||||
03
|
||||
#13
|
||||
#14
|
||||
#15
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
1,
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
13
|
||||
#16
|
||||
#17
|
||||
#18
|
||||
0,
|
||||
03
|
||||
#19
|
||||
#20
|
||||
|
|
|
|||
|
|
@ -1,19 +1,25 @@
|
|||
$version Generated by SpTraceVcd $end
|
||||
$date Thu Sep 18 07:55:56 2008
|
||||
$date Sat Sep 26 15:05:35 2009
|
||||
$end
|
||||
$timescale 1ns $end
|
||||
|
||||
$scope module TOP $end
|
||||
$var wire 1 + CLK $end
|
||||
$var wire 1 , RESET $end
|
||||
$var wire 1 2 CLK $end
|
||||
$var wire 1 3 RESET $end
|
||||
$scope module v $end
|
||||
$var wire 1 + CLK $end
|
||||
$var wire 1 2 CLK $end
|
||||
$var wire 1 # RESET $end
|
||||
$scope module glbl $end
|
||||
$var wire 1 - GSR $end
|
||||
$var wire 1 4 GSR $end
|
||||
$upscope $end
|
||||
$scope module little $end
|
||||
$var wire 1 2 clk $end
|
||||
$var wire 128 . i128 [63:190] $end
|
||||
$var wire 49 , i48 [1:49] $end
|
||||
$var wire 8 + i8 [0:7] $end
|
||||
$upscope $end
|
||||
$scope module neg $end
|
||||
$var wire 1 + clk $end
|
||||
$var wire 1 2 clk $end
|
||||
$var wire 128 ' i128 [63:-64] $end
|
||||
$var wire 48 % i48 [-1:-48] $end
|
||||
$var wire 8 $ i8 [0:-7] $end
|
||||
|
|
@ -28,44 +34,56 @@ $enddefinitions $end
|
|||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
1,
|
||||
0+
|
||||
1-
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
13
|
||||
02
|
||||
14
|
||||
#1
|
||||
#2
|
||||
#3
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
1+
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
12
|
||||
#4
|
||||
#5
|
||||
#6
|
||||
0+
|
||||
02
|
||||
#7
|
||||
0-
|
||||
04
|
||||
#8
|
||||
#9
|
||||
0#
|
||||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
0,
|
||||
1+
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
03
|
||||
12
|
||||
#10
|
||||
#11
|
||||
#12
|
||||
0+
|
||||
02
|
||||
#13
|
||||
#14
|
||||
#15
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
1+
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
12
|
||||
#16
|
||||
#17
|
||||
#18
|
||||
0+
|
||||
02
|
||||
#19
|
||||
#20
|
||||
|
|
|
|||
Loading…
Reference in New Issue