mirror of
https://github.com/verilator/verilator.git
synced 2026-08-22 05:57:29 +02:00
Support little endian bit vectors ("reg [0:2] x;").
This commit is contained in:
@@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||||||
|
|
||||||
* Verilator 3.71****
|
* Verilator 3.71****
|
||||||
|
|
||||||
|
** Support little endian bit vectors ("reg [0:2] x;").
|
||||||
|
|
||||||
**** Fix writing to out-of-bounds arrays writing element 0.
|
**** Fix writing to out-of-bounds arrays writing element 0.
|
||||||
|
|
||||||
**** Fix core dump with SystemVerilog var declarations under unnamed begins.
|
**** Fix core dump with SystemVerilog var declarations under unnamed begins.
|
||||||
|
|||||||
+12
-2
@@ -667,8 +667,8 @@ Disable the specified warning message.
|
|||||||
|
|
||||||
Disable all lint related warning messages. This is equivalent to
|
Disable all lint related warning messages. This is equivalent to
|
||||||
"-Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASEWITHX
|
"-Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASEWITHX
|
||||||
-Wno-CMPCONST -Wno-IMPLICIT -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED
|
-Wno-CMPCONST -Wno-IMPLICIT -Wno-LITENDIAN -Wno-UNDRIVEN -Wno-UNSIGNED
|
||||||
-Wno-VARHIDDEN -Wno-WIDTH".
|
-Wno-UNUSED -Wno-VARHIDDEN -Wno-WIDTH".
|
||||||
|
|
||||||
It is strongly recommended you cleanup your code rather than using this
|
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
|
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
|
Ignoring this warning may make Verilator simulations differ from other
|
||||||
simulators.
|
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
|
=item MULTIDRIVEN
|
||||||
|
|
||||||
Warns that the specified signal comes from multiple always blocks. This is
|
Warns that the specified signal comes from multiple always blocks. This is
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ RAW_OBJS = \
|
|||||||
V3Unknown.o \
|
V3Unknown.o \
|
||||||
V3Unroll.o \
|
V3Unroll.o \
|
||||||
V3Width.o \
|
V3Width.o \
|
||||||
|
V3WidthSel.o \
|
||||||
|
|
||||||
# Non-concatable
|
# Non-concatable
|
||||||
OBJS += \
|
OBJS += \
|
||||||
|
|||||||
+5
-3
@@ -170,9 +170,8 @@ class AstAttrType {
|
|||||||
public:
|
public:
|
||||||
enum en {
|
enum en {
|
||||||
BITS, // V3Const converts to constant
|
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, // V3LinkParse moves to AstVar::attrScClocked
|
||||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||||
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
||||||
@@ -182,7 +181,7 @@ public:
|
|||||||
enum en m_e;
|
enum en m_e;
|
||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
static const char* names[] = {
|
static const char* names[] = {
|
||||||
"BITS", "RANGE_LSB", "ARRAY_LSB",
|
"BITS", "VAR_BASE",
|
||||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
||||||
"VAR_ISOLATE_ASSIGNMENTS"
|
"VAR_ISOLATE_ASSIGNMENTS"
|
||||||
};
|
};
|
||||||
@@ -942,11 +941,14 @@ struct AstNodePreSel : public AstNode {
|
|||||||
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
|
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
|
||||||
ASTNODE_BASE_FUNCS(NodePreSel)
|
ASTNODE_BASE_FUNCS(NodePreSel)
|
||||||
AstNode* lhsp() const { return op1p()->castNode(); }
|
AstNode* lhsp() const { return op1p()->castNode(); }
|
||||||
|
AstNode* fromp() const { return lhsp(); }
|
||||||
AstNode* rhsp() const { return op2p()->castNode(); }
|
AstNode* rhsp() const { return op2p()->castNode(); }
|
||||||
AstNode* thsp() const { return op3p()->castNode(); }
|
AstNode* thsp() const { return op3p()->castNode(); }
|
||||||
|
AstAttrOf* attrp() const { return op4p()->castAttrOf(); }
|
||||||
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
||||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||||
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
||||||
|
void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); }
|
||||||
// METHODS
|
// METHODS
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
virtual bool same(AstNode*) const { return true; }
|
virtual bool same(AstNode*) const { return true; }
|
||||||
|
|||||||
@@ -141,6 +141,14 @@ AstRange* AstVar::arrayp(int dimension) const {
|
|||||||
return NULL;
|
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 AstVar::arrayElements() const {
|
||||||
uint32_t entries=1;
|
uint32_t entries=1;
|
||||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||||
@@ -149,6 +157,37 @@ uint32_t AstVar::arrayElements() const {
|
|||||||
return entries;
|
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 {
|
bool AstScope::broken() const {
|
||||||
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|
||||||
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|
||||||
@@ -303,6 +342,10 @@ void AstPin::dump(ostream& str) {
|
|||||||
else { str<<" ->UNLINKED"; }
|
else { str<<" ->UNLINKED"; }
|
||||||
if (svImplicit()) str<<" [.SV]";
|
if (svImplicit()) str<<" [.SV]";
|
||||||
}
|
}
|
||||||
|
void AstRange::dump(ostream& str) {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (littleEndian()) str<<" [LITTLE]";
|
||||||
|
}
|
||||||
void AstVarXRef::dump(ostream& str) {
|
void AstVarXRef::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (lvalue()) str<<" [LV] => ";
|
if (lvalue()) str<<" [LV] => ";
|
||||||
|
|||||||
+32
-19
@@ -76,20 +76,30 @@ public:
|
|||||||
|
|
||||||
struct AstRange : public AstNode {
|
struct AstRange : public AstNode {
|
||||||
// Range specification, for use under variables and cells
|
// 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)
|
AstRange(FileLine* fl, AstNode* msbp, AstNode* lsbp)
|
||||||
:AstNode(fl) {
|
:AstNode(fl) {
|
||||||
|
m_littleEndian = false;
|
||||||
setOp2p(msbp); setOp3p(lsbp); }
|
setOp2p(msbp); setOp3p(lsbp); }
|
||||||
AstRange(FileLine* fl, int msb, int lsb)
|
AstRange(FileLine* fl, int msb, int lsb)
|
||||||
:AstNode(fl) {
|
:AstNode(fl) {
|
||||||
|
m_littleEndian = false;
|
||||||
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
|
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
|
||||||
width(msb-lsb+1,msb-lsb+1);
|
width(msb-lsb+1,msb-lsb+1);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(Range, RANGE)
|
ASTNODE_NODE_FUNCS(Range, RANGE)
|
||||||
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
|
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
|
||||||
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb 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 msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||||
int lsbConst() const { AstConst* constp=lsbp()->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 string emitC() { V3ERROR_NA; return ""; }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
virtual bool same(AstNode* samep) const { return true; }
|
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 bool same(AstNode* samep) const { return true; }
|
||||||
virtual int instrCount() const { return widthInstrs(); }
|
virtual int instrCount() const { return widthInstrs(); }
|
||||||
// Special operators
|
// Special operators
|
||||||
static int dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
|
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
|
||||||
int dim = 0;
|
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstWordSel : public AstNodeSel {
|
struct AstWordSel : public AstNodeSel {
|
||||||
@@ -153,6 +156,8 @@ struct AstSelExtract : public AstNodePreSel {
|
|||||||
AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp)
|
AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp)
|
||||||
: AstNodePreSel(fl, fromp, msbp, lsbp) {}
|
: AstNodePreSel(fl, fromp, msbp, lsbp) {}
|
||||||
ASTNODE_NODE_FUNCS(SelExtract, SELEXTRACT)
|
ASTNODE_NODE_FUNCS(SelExtract, SELEXTRACT)
|
||||||
|
AstNode* msbp() const { return rhsp(); }
|
||||||
|
AstNode* lsbp() const { return thsp(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstSelBit : public AstNodePreSel {
|
struct AstSelBit : public AstNodePreSel {
|
||||||
@@ -163,6 +168,7 @@ struct AstSelBit : public AstNodePreSel {
|
|||||||
width(1,1);
|
width(1,1);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(SelBit, SELBIT)
|
ASTNODE_NODE_FUNCS(SelBit, SELBIT)
|
||||||
|
AstNode* bitp() const { return rhsp(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstSelPlus : public AstNodePreSel {
|
struct AstSelPlus : public AstNodePreSel {
|
||||||
@@ -171,6 +177,8 @@ struct AstSelPlus : public AstNodePreSel {
|
|||||||
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||||
ASTNODE_NODE_FUNCS(SelPlus, SELPLUS)
|
ASTNODE_NODE_FUNCS(SelPlus, SELPLUS)
|
||||||
|
AstNode* bitp() const { return rhsp(); }
|
||||||
|
AstNode* widthp() const { return thsp(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstSelMinus : public AstNodePreSel {
|
struct AstSelMinus : public AstNodePreSel {
|
||||||
@@ -179,6 +187,8 @@ struct AstSelMinus : public AstNodePreSel {
|
|||||||
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
|
||||||
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
:AstNodePreSel(fl, fromp, bitp, widthp) {}
|
||||||
ASTNODE_NODE_FUNCS(SelMinus, SELMINUS)
|
ASTNODE_NODE_FUNCS(SelMinus, SELMINUS)
|
||||||
|
AstNode* bitp() const { return rhsp(); }
|
||||||
|
AstNode* widthp() const { return thsp(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstSel : public AstNodeTriop {
|
struct AstSel : public AstNodeTriop {
|
||||||
@@ -358,7 +368,11 @@ public:
|
|||||||
int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,...
|
int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,...
|
||||||
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
||||||
int lsb() const { if (!rangep()) return 0; return rangep()->lsbConst(); }
|
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
|
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
|
uint32_t arrayElements() const; // 1, or total multiplication of all dimensions
|
||||||
virtual string verilogKwd() const;
|
virtual string verilogKwd() const;
|
||||||
void propagateAttrFrom(AstVar* fromp) {
|
void propagateAttrFrom(AstVar* fromp) {
|
||||||
@@ -1620,7 +1634,7 @@ public:
|
|||||||
widthSignedFrom(varp);
|
widthSignedFrom(varp);
|
||||||
m_code = 0;
|
m_code = 0;
|
||||||
m_codeInc = varp->arrayElements() * varp->widthWords();
|
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_arrayLsb = varp->arrayp(0) ? varp->arrayp(0)->lsbConst() : 0;
|
||||||
m_arrayMsb = varp->arrayp(0) ? varp->arrayp(0)->msbConst() : 0;
|
m_arrayMsb = varp->arrayp(0) ? varp->arrayp(0)->msbConst() : 0;
|
||||||
}
|
}
|
||||||
@@ -1634,8 +1648,8 @@ public:
|
|||||||
uint32_t code() const { return m_code; }
|
uint32_t code() const { return m_code; }
|
||||||
void code(uint32_t code) { m_code=code; }
|
void code(uint32_t code) { m_code=code; }
|
||||||
uint32_t codeInc() const { return m_codeInc; }
|
uint32_t codeInc() const { return m_codeInc; }
|
||||||
int msb() const { return m_msb; }
|
int msbEndianed() const { return m_msb; } // Note msb maybe < lsb if little endian
|
||||||
int lsb() const { return m_lsb; }
|
int lsbEndianed() const { return m_lsb; }
|
||||||
uint32_t arrayMsb() const { return m_arrayMsb; }
|
uint32_t arrayMsb() const { return m_arrayMsb; }
|
||||||
uint32_t arrayLsb() const { return m_arrayLsb; }
|
uint32_t arrayLsb() const { return m_arrayLsb; }
|
||||||
uint32_t arrayWidth() const { if (!arrayMsb()) return 0; return arrayMsb()-arrayLsb()+1; }
|
uint32_t arrayWidth() const { if (!arrayMsb()) return 0; return arrayMsb()-arrayLsb()+1; }
|
||||||
@@ -1717,15 +1731,14 @@ struct AstAttrOf : public AstNode {
|
|||||||
private:
|
private:
|
||||||
// Return a value of a attribute, for example a LSB or array LSB of a signal
|
// Return a value of a attribute, for example a LSB or array LSB of a signal
|
||||||
AstAttrType m_attrType; // What sort of extraction
|
AstAttrType m_attrType; // What sort of extraction
|
||||||
int m_dimension; // Dimension number (0 is leftmost), for ARRAY_LSB extractions
|
|
||||||
public:
|
public:
|
||||||
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL, int dimension=0)
|
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL)
|
||||||
: AstNode(fl) {
|
: AstNode(fl) {
|
||||||
setNOp1p(fromp); m_attrType = attrtype; m_dimension = dimension; }
|
setNOp1p(fromp);
|
||||||
|
m_attrType = attrtype; }
|
||||||
ASTNODE_NODE_FUNCS(AttrOf, ATTROF)
|
ASTNODE_NODE_FUNCS(AttrOf, ATTROF)
|
||||||
AstNode* fromp() const { return op1p(); }
|
AstNode* fromp() const { return op1p(); }
|
||||||
AstAttrType attrType() const { return m_attrType; }
|
AstAttrType attrType() const { return m_attrType; }
|
||||||
int dimension() const { return m_dimension; }
|
|
||||||
virtual void dump(ostream& str=cout);
|
virtual void dump(ostream& str=cout);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+9
-19
@@ -1053,7 +1053,7 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||||
bool did=false;
|
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: ");
|
//if (debug()) nodep->varp()->initp()->dumpTree(cout," visitvaref: ");
|
||||||
nodep->varp()->initp()->iterateAndNext(*this);
|
nodep->varp()->initp()->iterateAndNext(*this);
|
||||||
if (operandConst(nodep->varp()->initp())
|
if (operandConst(nodep->varp()->initp())
|
||||||
@@ -1079,23 +1079,7 @@ private:
|
|||||||
V3Number num (nodep->fileline(), 32, nodep->fromp()->widthMin());
|
V3Number num (nodep->fileline(), 32, nodep->fromp()->widthMin());
|
||||||
replaceNum(nodep, num); nodep=NULL;
|
replaceNum(nodep, num); nodep=NULL;
|
||||||
} else {
|
} else {
|
||||||
if (!nodep->fromp()->castNodeVarRef()) nodep->v3fatalSrc("Not linked");
|
nodep->v3fatalSrc("Missing ATTR type case");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool onlySenItemInSenTree(AstNodeSenItem* nodep) {
|
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
|
// Below lines are magic expressions processed by astgen
|
||||||
// "AstNODETYPE { # bracket not paren
|
// "AstNODETYPE { # bracket not paren
|
||||||
@@ -1746,7 +1734,9 @@ public:
|
|||||||
|
|
||||||
AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
|
AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
|
||||||
//if (debug()>0) nodep->dumpTree(cout," forceConPRE : ");
|
//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);
|
ConstVisitor visitor (true,false,false,false);
|
||||||
if (AstVar* varp=nodep->castVar()) {
|
if (AstVar* varp=nodep->castVar()) {
|
||||||
// If a var wants to be constified, it's really a param, and
|
// If a var wants to be constified, it's really a param, and
|
||||||
|
|||||||
+5
-5
@@ -1839,7 +1839,7 @@ class EmitCTrace : EmitCStmts {
|
|||||||
puts("vcdp->declArray");
|
puts("vcdp->declArray");
|
||||||
} else if (nodep->isQuad()) {
|
} else if (nodep->isQuad()) {
|
||||||
puts("vcdp->declQuad ");
|
puts("vcdp->declQuad ");
|
||||||
} else if (nodep->msb() || nodep->lsb()) {
|
} else if (nodep->msbEndianed() || nodep->lsbEndianed()) {
|
||||||
puts("vcdp->declBus ");
|
puts("vcdp->declBus ");
|
||||||
} else {
|
} else {
|
||||||
puts("vcdp->declBit ");
|
puts("vcdp->declBit ");
|
||||||
@@ -1853,8 +1853,8 @@ class EmitCTrace : EmitCStmts {
|
|||||||
} else {
|
} else {
|
||||||
puts(",-1");
|
puts(",-1");
|
||||||
}
|
}
|
||||||
if (nodep->msb() || nodep->lsb()) {
|
if (nodep->msbEndianed() || nodep->lsbEndianed()) {
|
||||||
puts(","+cvtToStr(nodep->msb())+","+cvtToStr(nodep->lsb()));
|
puts(","+cvtToStr(nodep->msbEndianed())+","+cvtToStr(nodep->lsbEndianed()));
|
||||||
}
|
}
|
||||||
puts(");");
|
puts(");");
|
||||||
}
|
}
|
||||||
@@ -1868,7 +1868,7 @@ class EmitCTrace : EmitCStmts {
|
|||||||
puts("vcdp->"+full+"Array");
|
puts("vcdp->"+full+"Array");
|
||||||
} else if (nodep->isQuad()) {
|
} else if (nodep->isQuad()) {
|
||||||
puts("vcdp->"+full+"Quad ");
|
puts("vcdp->"+full+"Quad ");
|
||||||
} else if (nodep->declp()->msb() || nodep->declp()->lsb()) {
|
} else if (nodep->declp()->msbEndianed() || nodep->declp()->lsbEndianed()) {
|
||||||
puts("vcdp->"+full+"Bus ");
|
puts("vcdp->"+full+"Bus ");
|
||||||
} else {
|
} else {
|
||||||
puts("vcdp->"+full+"Bit ");
|
puts("vcdp->"+full+"Bit ");
|
||||||
@@ -1877,7 +1877,7 @@ class EmitCTrace : EmitCStmts {
|
|||||||
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
|
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
|
||||||
puts(",");
|
puts(",");
|
||||||
emitTraceValue(nodep, arrayindex);
|
emitTraceValue(nodep, arrayindex);
|
||||||
if (nodep->declp()->msb() || nodep->declp()->lsb()) {
|
if (nodep->declp()->msbEndianed() || nodep->declp()->lsbEndianed()) {
|
||||||
puts(","+cvtToStr(nodep->declp()->widthMin()));
|
puts(","+cvtToStr(nodep->declp()->widthMin()));
|
||||||
}
|
}
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
|
|||||||
+2
-2
@@ -368,8 +368,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
}
|
}
|
||||||
virtual void visit(AstRange* nodep, AstNUser*) {
|
virtual void visit(AstRange* nodep, AstNUser*) {
|
||||||
puts("[");
|
puts("[");
|
||||||
nodep->msbp()->iterateAndNext(*this); puts(":");
|
nodep->msbEndianedp()->iterateAndNext(*this); puts(":");
|
||||||
nodep->lsbp()->iterateAndNext(*this); puts("]");
|
nodep->lsbEndianedp()->iterateAndNext(*this); puts("]");
|
||||||
}
|
}
|
||||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||||
nodep->fromp()->iterateAndNext(*this); puts("[");
|
nodep->fromp()->iterateAndNext(*this); puts("[");
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public:
|
|||||||
IMPERFECTSCH, // Imperfect schedule (disabled by default)
|
IMPERFECTSCH, // Imperfect schedule (disabled by default)
|
||||||
IMPLICIT, // Implicit wire
|
IMPLICIT, // Implicit wire
|
||||||
IMPURE, // Impure function not being inlined
|
IMPURE, // Impure function not being inlined
|
||||||
|
LITENDIAN, // Little bit endian vector
|
||||||
MULTIDRIVEN, // Driven from multiple blocks
|
MULTIDRIVEN, // Driven from multiple blocks
|
||||||
REDEFMACRO, // Redefining existing define macro
|
REDEFMACRO, // Redefining existing define macro
|
||||||
UNDRIVEN, // No drivers
|
UNDRIVEN, // No drivers
|
||||||
@@ -96,6 +97,7 @@ public:
|
|||||||
"BLKANDNBLK",
|
"BLKANDNBLK",
|
||||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CMPCONST",
|
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CMPCONST",
|
||||||
"COMBDLY", "STMTDLY", "SYMRSVDWORD", "GENCLK", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
|
"COMBDLY", "STMTDLY", "SYMRSVDWORD", "GENCLK", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
|
||||||
|
"LITENDIAN",
|
||||||
"MULTIDRIVEN", "REDEFMACRO",
|
"MULTIDRIVEN", "REDEFMACRO",
|
||||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
||||||
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
|
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
|
||||||
@@ -118,6 +120,7 @@ public:
|
|||||||
|| m_e==CASEWITHX || m_e==CASEX
|
|| m_e==CASEWITHX || m_e==CASEX
|
||||||
|| m_e==CMPCONST
|
|| m_e==CMPCONST
|
||||||
|| m_e==IMPLICIT
|
|| m_e==IMPLICIT
|
||||||
|
|| m_e==LITENDIAN
|
||||||
|| m_e==UNDRIVEN || m_e==UNSIGNED
|
|| m_e==UNDRIVEN || m_e==UNSIGNED
|
||||||
|| m_e==UNUSED || m_e==VARHIDDEN
|
|| m_e==UNUSED || m_e==VARHIDDEN
|
||||||
|| m_e==WIDTH); }
|
|| m_e==WIDTH); }
|
||||||
|
|||||||
+17
-144
@@ -160,6 +160,11 @@ private:
|
|||||||
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
||||||
did=1;
|
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()) {
|
if (!nodep->sensp()->castNodeVarRef()) {
|
||||||
@@ -171,151 +176,19 @@ private:
|
|||||||
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
|
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
void iterateSelTriop(AstNodePreSel* nodep) {
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
if (!nodep->attrp()) {
|
||||||
}
|
nodep->iterateChildren(*this);
|
||||||
|
// Constification may change the fromp() to a constant, which will loose the
|
||||||
AstNode* newSubAttrOf(AstNode* underp, AstNode* fromp, AstAttrType attrType) {
|
// variable we're extracting from (to determine MSB/LSB/endianness/etc.)
|
||||||
// Account for a variable's LSB in bit selections
|
// So we replicate it in another node
|
||||||
// Replace underp with a SUB(underp, ATTROF(varp, attrType))
|
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
|
||||||
int dimension=0;
|
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||||
while (fromp && !fromp->castNodeVarRef() && (fromp->castSel() || fromp->castArraySel())) {
|
AstNodeVarRef* varrefp = basefromp->castNodeVarRef(); // Maybe varxref - so need to clone
|
||||||
if (fromp->castSel()) fromp = fromp->castSel()->fromp();
|
if (!varrefp) nodep->v3fatalSrc("Illegal bit select; no signal being extracted from");
|
||||||
else fromp = fromp->castArraySel()->fromp();
|
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||||
dimension++;
|
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*) {
|
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
||||||
|
|||||||
+19
-4
@@ -55,7 +55,9 @@ private:
|
|||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstModule::user4() // bool True if parameters numbered
|
// AstModule::user4() // bool True if parameters numbered
|
||||||
// AstVar::user4() // int Global parameter number (for naming new module)
|
// AstVar::user4() // int Global parameter number (for naming new module)
|
||||||
|
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
|
||||||
AstUser4InUse m_inuser4;
|
AstUser4InUse m_inuser4;
|
||||||
|
// User1/2/3 used by constant function simulations
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
typedef std::map<AstVar*,AstVar*> VarCloneMap;
|
typedef std::map<AstVar*,AstVar*> VarCloneMap;
|
||||||
@@ -93,7 +95,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
string paramSmallName(AstModule* modp, AstVar* varp) {
|
string paramSmallName(AstModule* modp, AstVar* varp) {
|
||||||
if (!varp->user4()) {
|
if (varp->user4()<=1) {
|
||||||
makeSmallNames(modp);
|
makeSmallNames(modp);
|
||||||
}
|
}
|
||||||
int index = varp->user4()/256;
|
int index = varp->user4()/256;
|
||||||
@@ -129,11 +131,19 @@ private:
|
|||||||
|
|
||||||
// Make sure all parameters are constantified
|
// Make sure all parameters are constantified
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
if (nodep->isParam()) {
|
if (!nodep->user4()) {
|
||||||
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
nodep->user4(1); // Mark done - Note values >1 used for letter numbering
|
||||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
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
|
// Generate Statements
|
||||||
virtual void visit(AstGenerate* nodep, AstNUser*) {
|
virtual void visit(AstGenerate* nodep, AstNUser*) {
|
||||||
@@ -151,6 +161,7 @@ private:
|
|||||||
nodep->deleteTree(); nodep=NULL;
|
nodep->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstGenIf* nodep, AstNUser*) {
|
virtual void visit(AstGenIf* nodep, AstNUser*) {
|
||||||
|
nodep->condp()->iterateAndNext(*this);
|
||||||
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
||||||
V3Const::constifyParamsEdit(nodep->condp()); // condp may change
|
V3Const::constifyParamsEdit(nodep->condp()); // condp may change
|
||||||
if (AstConst* constp = nodep->condp()->castConst()) {
|
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
|
// We parse a very limited form of FOR, so we don't need to do a full
|
||||||
// simulation to unroll the loop
|
// simulation to unroll the loop
|
||||||
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
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;
|
V3Unroll::unrollGen(nodep); nodep=NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstGenCase* nodep, AstNUser*) {
|
virtual void visit(AstGenCase* nodep, AstNUser*) {
|
||||||
AstNode* keepp = NULL;
|
AstNode* keepp = NULL;
|
||||||
|
nodep->exprp()->iterateAndNext(*this);
|
||||||
V3Case::caseLint(nodep);
|
V3Case::caseLint(nodep);
|
||||||
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
|
||||||
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
|
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
|
||||||
@@ -185,6 +198,7 @@ private:
|
|||||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||||
for (AstNode* ep = itemp->condsp(); ep; ) {
|
for (AstNode* ep = itemp->condsp(); ep; ) {
|
||||||
AstNode* nextp = ep->nextp(); //May edit list
|
AstNode* nextp = ep->nextp(); //May edit list
|
||||||
|
ep->iterateAndNext(*this);
|
||||||
V3Const::constifyParamsEdit(ep); ep=NULL; // ep may change
|
V3Const::constifyParamsEdit(ep); ep=NULL; // ep may change
|
||||||
ep = nextp;
|
ep = nextp;
|
||||||
}
|
}
|
||||||
@@ -240,6 +254,7 @@ public:
|
|||||||
|
|
||||||
void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
|
void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
|
||||||
// Cell: Check for parameters in the instantiation.
|
// Cell: Check for parameters in the instantiation.
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
|
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
|
||||||
if (nodep->paramsp()) {
|
if (nodep->paramsp()) {
|
||||||
UINFO(4,"De-parameterize: "<<nodep<<endl);
|
UINFO(4,"De-parameterize: "<<nodep<<endl);
|
||||||
|
|||||||
+1
-1
@@ -503,7 +503,7 @@ private:
|
|||||||
UINFO(5," FUNCREF "<<nodep<<endl);
|
UINFO(5," FUNCREF "<<nodep<<endl);
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
AstFunc* funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
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");
|
funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||||
// Apply function call values to function
|
// Apply function call values to function
|
||||||
// Note we'd need a stack if we allowed recursive functions!
|
// Note we'd need a stack if we allowed recursive functions!
|
||||||
|
|||||||
+2
-1
@@ -388,7 +388,8 @@ private:
|
|||||||
if (m_varModeReplace
|
if (m_varModeReplace
|
||||||
&& nodep->varp() == m_forVarp
|
&& nodep->varp() == m_forVarp
|
||||||
&& nodep->varScopep() == m_forVscp
|
&& nodep->varScopep() == m_forVscp
|
||||||
&& !nodep->lvalue()) {
|
&& !nodep->lvalue()
|
||||||
|
&& !nodep->backp()->castAttrOf()) { // Most likely under a select
|
||||||
AstNode* newconstp = m_varValuep->cloneTree(false);
|
AstNode* newconstp = m_varValuep->cloneTree(false);
|
||||||
nodep->replaceWith(newconstp);
|
nodep->replaceWith(newconstp);
|
||||||
pushDeletep(nodep);
|
pushDeletep(nodep);
|
||||||
|
|||||||
+88
-45
@@ -249,39 +249,20 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstRange* nodep, AstNUser* vup) {
|
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()) {
|
if (vup->c()->prelim()) {
|
||||||
nodep->msbp()->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());
|
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
V3Const::constifyParamsEdit(nodep->msbp()); // msbp may change
|
int width = nodep->elementsConst();
|
||||||
V3Const::constifyParamsEdit(nodep->lsbp()); // lsbp may change
|
if (width > (1<<28)) nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x"<<hex<<width);
|
||||||
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;
|
|
||||||
nodep->width(width,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) {
|
virtual void visit(AstSel* nodep, AstNUser* vup) {
|
||||||
if (vup->c()->prelim()) {
|
if (vup->c()->prelim()) {
|
||||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||||
@@ -383,6 +364,54 @@ private:
|
|||||||
widthCheck(nodep,"Extract Range",nodep->bitp(),selwidth,selwidth,true);
|
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) {
|
virtual void visit(AstExtend* nodep, AstNUser* vup) {
|
||||||
// Only created by this process, so we know width from here down it is correct.
|
// 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;
|
int selwidth = V3Number::log2b(nodep->lhsp()->width())+1;
|
||||||
nodep->width(selwidth,selwidth);
|
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->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
nodep->width(32,1); // Approximation, unsized 32
|
nodep->width(32,1); // Approximation, unsized 32
|
||||||
}
|
}
|
||||||
@@ -526,8 +555,9 @@ private:
|
|||||||
AstNodeCase* lastCasep = m_casep;
|
AstNodeCase* lastCasep = m_casep;
|
||||||
m_casep = nodep;
|
m_casep = nodep;
|
||||||
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
for (AstCaseItem* nextp, *itemp = nodep->itemsp(); itemp; itemp=nextp) {
|
||||||
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
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 width = nodep->exprp()->width();
|
||||||
int mwidth = nodep->exprp()->widthMin();
|
int mwidth = nodep->exprp()->widthMin();
|
||||||
@@ -552,8 +582,11 @@ private:
|
|||||||
// Need to look across multiple case values for one set of statements
|
// Need to look across multiple case values for one set of statements
|
||||||
int width = nodep->condsp()->width();
|
int width = nodep->condsp()->width();
|
||||||
int mwidth = nodep->condsp()->widthMin();
|
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()) {
|
for (AstNode* condp = nodep->condsp(); condp; condp=condp->nextp()) {
|
||||||
condp->iterate(*this,vup);
|
|
||||||
width = max(width,condp->width());
|
width = max(width,condp->width());
|
||||||
mwidth = max(mwidth,condp->widthMin());
|
mwidth = max(mwidth,condp->widthMin());
|
||||||
if (vup->c()->final()) {
|
if (vup->c()->final()) {
|
||||||
@@ -804,19 +837,25 @@ private:
|
|||||||
m_taskDepth--;
|
m_taskDepth--;
|
||||||
}
|
}
|
||||||
// And do the arguments to the task/function too
|
// And do the arguments to the task/function too
|
||||||
AstNode* pinp = nodep->pinsp();
|
for (int accept_mode=1; accept_mode>=0; accept_mode--) { // Avoid duplicate code; just do inner stuff twice
|
||||||
AstNode* stmt_nextp; // List may change, so need to keep pointer
|
AstNode* pinp = nodep->pinsp();
|
||||||
for (AstNode* stmtp = nodep->taskp()->stmtsp(); stmtp; stmtp=stmt_nextp) {
|
for (AstNode* stmt_nextp, *stmtp = nodep->taskp()->stmtsp(); stmtp; stmtp=stmt_nextp) {
|
||||||
stmt_nextp = stmtp->nextp();
|
stmt_nextp = stmtp->nextp();
|
||||||
if (AstVar* portp = stmtp->castVar()) {
|
if (AstVar* portp = stmtp->castVar()) {
|
||||||
if (portp->isIO()
|
if (portp->isIO()
|
||||||
&& pinp!=NULL) { // Else argument error we'll find later
|
&& pinp!=NULL) { // Else argument error we'll find later
|
||||||
AstNode* pin_nextp = pinp->nextp(); // List may change, so remember nextp
|
AstNode* pin_nextp = pinp->nextp(); // List may change, so remember nextp
|
||||||
int width = portp->width();
|
if (accept_mode) {
|
||||||
int ewidth = portp->widthMin();
|
// Prelim may cause the node to get replaced; we've lost our
|
||||||
pinp->accept(*this,WidthVP(width,ewidth,BOTH).p());
|
// pointer, so need to iterate separately later
|
||||||
widthCheck(nodep,"Function Argument",pinp,width,ewidth);
|
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
|
||||||
pinp = pin_nextp;
|
} 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->width(nodep->width(),nodep->width());
|
||||||
nodep->iterateChildren(*this);
|
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:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
WidthCommitVisitor(AstNetlist* nodep) {
|
WidthCommitVisitor(AstNetlist* nodep) {
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ public:
|
|||||||
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
|
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
|
||||||
// Final step... Mark all widths as equal
|
// Final step... Mark all widths as equal
|
||||||
static void widthCommit(AstNetlist* nodep);
|
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
|
#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},
|
fails=>$Self->{v3},
|
||||||
nc=>0, # Need to get it not to give the prompt
|
nc=>0, # Need to get it not to give the prompt
|
||||||
expect=>
|
expect=>
|
||||||
'%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
|
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 select; variable already selected, or bad dimension
|
.*%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 select; variable already selected, or bad dimension
|
.*%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; variable already selected, or bad dimension
|
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||||
%Error: Exiting due to.*',
|
.*%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);
|
ok(1);
|
||||||
|
|||||||
@@ -4,15 +4,19 @@
|
|||||||
// without warranty, 2005 by Wilson Snyder.
|
// without warranty, 2005 by Wilson Snyder.
|
||||||
|
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/);
|
||||||
|
reg dimn;
|
||||||
reg [1:0] dim0;
|
reg [1:0] dim0;
|
||||||
reg [1:0] dim1 [1:0];
|
reg [1:0] dim1 [1:0];
|
||||||
reg [1:0] dim2 [1:0][1:0];
|
reg [1:0] dim2 [1:0][1:0];
|
||||||
reg dim0nv[1:0];
|
reg dim0nv[1:0];
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
dimn[1:0] = 0; // Bad: Not ranged
|
||||||
dim0[1][1] = 0; // Bad: Not arrayed
|
dim0[1][1] = 0; // Bad: Not arrayed
|
||||||
dim1[1][1][1] = 0; // Bad: Not arrayed to right depth
|
dim1[1][1][1] = 0; // Bad: Not arrayed to right depth
|
||||||
dim2[1][1][1] = 0; // OK
|
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
|
dim2[1][1:0] = 0; // Bad: Bitsel too soon
|
||||||
dim0nv[1:0] = 0; // Bad: Not vectored
|
dim0nv[1:0] = 0; // Bad: Not vectored
|
||||||
dim0nv[1][1] = 0; // Bad: Not arrayed to right depth
|
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 (
|
compile (
|
||||||
fails=>1,
|
fails=>1,
|
||||||
expect=>
|
expect=>
|
||||||
'%Error: t/t_select_bad_msb.v:\d+: Unsupported: MSB < LSB of bit range: 0<22
|
'%Warning-LITENDIAN: t/t_select_bad_msb.v:\d+: Little bit endian vector: MSB < LSB of bit range: 0:22
|
||||||
%Error: t/t_select_bad_msb.v:\d+: Unsupported: MSB < LSB of bit extract: 1<4
|
.*
|
||||||
%Error: Exiting due to.*',
|
%Error: Exiting due to.*',
|
||||||
) if $Self->{v3};
|
) if $Self->{v3};
|
||||||
|
|
||||||
|
|||||||
Executable
+18
@@ -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));
|
neg neg (.clk(CLK));
|
||||||
|
little little (.clk(CLK));
|
||||||
glbl glbl ();
|
glbl glbl ();
|
||||||
|
|
||||||
initial RESET = 1'b1;
|
initial RESET = 1'b1;
|
||||||
@@ -43,5 +44,21 @@ module neg (
|
|||||||
i48 <= ~i48;
|
i48 <= ~i48;
|
||||||
i128 <= ~i128;
|
i128 <= ~i128;
|
||||||
end
|
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
|
endmodule
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
$version Generated by SpTraceVcd $end
|
$version Generated by SpTraceVcd $end
|
||||||
$date Thu Sep 18 07:54:41 2008
|
$date Sat Sep 26 15:04:50 2009
|
||||||
$end
|
$end
|
||||||
$timescale 1ns $end
|
$timescale 1ns $end
|
||||||
|
|
||||||
$scope module TOP $end
|
$scope module TOP $end
|
||||||
$var wire 1 , CLK $end
|
$var wire 1 3 CLK $end
|
||||||
$var wire 1 - RESET $end
|
$var wire 1 4 RESET $end
|
||||||
$scope module v $end
|
$scope module v $end
|
||||||
$var wire 1 , CLK $end
|
$var wire 1 3 CLK $end
|
||||||
$var wire 1 # RESET $end
|
$var wire 1 # RESET $end
|
||||||
$scope module glbl $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
|
$upscope $end
|
||||||
$scope module neg $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 128 ' i128 [63:-64] $end
|
||||||
$var wire 48 % i48 [-1:-48] $end
|
$var wire 48 % i48 [-1:-48] $end
|
||||||
$var wire 8 $ i8 [0:-7] $end
|
$var wire 8 $ i8 [0:-7] $end
|
||||||
@@ -28,44 +34,56 @@ $enddefinitions $end
|
|||||||
b00000000 $
|
b00000000 $
|
||||||
b000000000000000000000000000000000000000000000000 %
|
b000000000000000000000000000000000000000000000000 %
|
||||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||||
1+
|
b00000000 +
|
||||||
1-
|
b0000000000000000000000000000000000000000000000000 ,
|
||||||
0,
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||||
|
12
|
||||||
|
14
|
||||||
|
03
|
||||||
#1
|
#1
|
||||||
#2
|
#2
|
||||||
#3
|
#3
|
||||||
b11111111 $
|
b11111111 $
|
||||||
b111111111111111111111111111111111111111111111111 %
|
b111111111111111111111111111111111111111111111111 %
|
||||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||||
1,
|
b11111111 +
|
||||||
|
b1111111111111111111111111111111111111111111111111 ,
|
||||||
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||||
|
13
|
||||||
#4
|
#4
|
||||||
#5
|
#5
|
||||||
#6
|
#6
|
||||||
0,
|
03
|
||||||
#7
|
#7
|
||||||
0+
|
02
|
||||||
#8
|
#8
|
||||||
#9
|
#9
|
||||||
0#
|
0#
|
||||||
b00000000 $
|
b00000000 $
|
||||||
b000000000000000000000000000000000000000000000000 %
|
b000000000000000000000000000000000000000000000000 %
|
||||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||||
0-
|
b00000000 +
|
||||||
1,
|
b0000000000000000000000000000000000000000000000000 ,
|
||||||
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||||
|
04
|
||||||
|
13
|
||||||
#10
|
#10
|
||||||
#11
|
#11
|
||||||
#12
|
#12
|
||||||
0,
|
03
|
||||||
#13
|
#13
|
||||||
#14
|
#14
|
||||||
#15
|
#15
|
||||||
b11111111 $
|
b11111111 $
|
||||||
b111111111111111111111111111111111111111111111111 %
|
b111111111111111111111111111111111111111111111111 %
|
||||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||||
1,
|
b11111111 +
|
||||||
|
b1111111111111111111111111111111111111111111111111 ,
|
||||||
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||||
|
13
|
||||||
#16
|
#16
|
||||||
#17
|
#17
|
||||||
#18
|
#18
|
||||||
0,
|
03
|
||||||
#19
|
#19
|
||||||
#20
|
#20
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
$version Generated by SpTraceVcd $end
|
$version Generated by SpTraceVcd $end
|
||||||
$date Thu Sep 18 07:55:56 2008
|
$date Sat Sep 26 15:05:35 2009
|
||||||
$end
|
$end
|
||||||
$timescale 1ns $end
|
$timescale 1ns $end
|
||||||
|
|
||||||
$scope module TOP $end
|
$scope module TOP $end
|
||||||
$var wire 1 + CLK $end
|
$var wire 1 2 CLK $end
|
||||||
$var wire 1 , RESET $end
|
$var wire 1 3 RESET $end
|
||||||
$scope module v $end
|
$scope module v $end
|
||||||
$var wire 1 + CLK $end
|
$var wire 1 2 CLK $end
|
||||||
$var wire 1 # RESET $end
|
$var wire 1 # RESET $end
|
||||||
$scope module glbl $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
|
$upscope $end
|
||||||
$scope module neg $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 128 ' i128 [63:-64] $end
|
||||||
$var wire 48 % i48 [-1:-48] $end
|
$var wire 48 % i48 [-1:-48] $end
|
||||||
$var wire 8 $ i8 [0:-7] $end
|
$var wire 8 $ i8 [0:-7] $end
|
||||||
@@ -28,44 +34,56 @@ $enddefinitions $end
|
|||||||
b00000000 $
|
b00000000 $
|
||||||
b000000000000000000000000000000000000000000000000 %
|
b000000000000000000000000000000000000000000000000 %
|
||||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||||
1,
|
b00000000 +
|
||||||
0+
|
b0000000000000000000000000000000000000000000000000 ,
|
||||||
1-
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||||
|
13
|
||||||
|
02
|
||||||
|
14
|
||||||
#1
|
#1
|
||||||
#2
|
#2
|
||||||
#3
|
#3
|
||||||
b11111111 $
|
b11111111 $
|
||||||
b111111111111111111111111111111111111111111111111 %
|
b111111111111111111111111111111111111111111111111 %
|
||||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||||
1+
|
b11111111 +
|
||||||
|
b1111111111111111111111111111111111111111111111111 ,
|
||||||
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||||
|
12
|
||||||
#4
|
#4
|
||||||
#5
|
#5
|
||||||
#6
|
#6
|
||||||
0+
|
02
|
||||||
#7
|
#7
|
||||||
0-
|
04
|
||||||
#8
|
#8
|
||||||
#9
|
#9
|
||||||
0#
|
0#
|
||||||
b00000000 $
|
b00000000 $
|
||||||
b000000000000000000000000000000000000000000000000 %
|
b000000000000000000000000000000000000000000000000 %
|
||||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||||
0,
|
b00000000 +
|
||||||
1+
|
b0000000000000000000000000000000000000000000000000 ,
|
||||||
|
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||||
|
03
|
||||||
|
12
|
||||||
#10
|
#10
|
||||||
#11
|
#11
|
||||||
#12
|
#12
|
||||||
0+
|
02
|
||||||
#13
|
#13
|
||||||
#14
|
#14
|
||||||
#15
|
#15
|
||||||
b11111111 $
|
b11111111 $
|
||||||
b111111111111111111111111111111111111111111111111 %
|
b111111111111111111111111111111111111111111111111 %
|
||||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||||
1+
|
b11111111 +
|
||||||
|
b1111111111111111111111111111111111111111111111111 ,
|
||||||
|
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||||
|
12
|
||||||
#16
|
#16
|
||||||
#17
|
#17
|
||||||
#18
|
#18
|
||||||
0+
|
02
|
||||||
#19
|
#19
|
||||||
#20
|
#20
|
||||||
|
|||||||
Reference in New Issue
Block a user