diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 17cd6bc1f..0a4a17a81 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -269,7 +269,7 @@ AstNodeDType* AstVar::dtypeDimensionp(int dimension) const { } else if (AstBasicDType* adtypep = dtypep->castBasicDType()) { // AstBasicDType - nothing below, return null - if (adtypep->rangep()) { + if (adtypep->isRanged()) { if ((dim++) == dimension) { return adtypep; } @@ -524,6 +524,7 @@ void AstAttrOf::dump(ostream& str) { void AstBasicDType::dump(ostream& str) { this->AstNodeDType::dump(str); str<<" ["< 1) ? new AstRange(fl, wantwidth-1, 0) : NULL)); + init(AstBasicDTypeKwd::LOGIC, signedst_NOP, wantwidth, NULL); } AstBasicDType(FileLine* fl, AstBitPacked, int wantwidth) : AstNodeDType(fl) { - init(AstBasicDTypeKwd::BIT, signedst_NOP, - ((wantwidth > 1) ? new AstRange(fl, wantwidth-1, 0) : NULL)); + init(AstBasicDTypeKwd::BIT, signedst_NOP, wantwidth, NULL); } // See also addRange in verilog.y private: - void init(AstBasicDTypeKwd kwd, AstSignedState signst, AstRange* rangep) { + void init(AstBasicDTypeKwd kwd, AstSignedState signst, int wantwidth, AstRange* rangep) { m_keyword = kwd; + m_msb = 0; // Implicitness: // "parameter X" is implicit and sized from initial value, "parameter reg x" not m_implicit = false; if (keyword()==AstBasicDTypeKwd::LOGIC_IMPLICIT) { - if (!rangep) m_implicit = true; // Also cleared if range added later + if (!rangep && !wantwidth) m_implicit = true; // Also cleared if range added later m_keyword = AstBasicDTypeKwd::LOGIC; } if (signst == signedst_NOP && keyword().isSigned()) signst = signedst_SIGNED; if (keyword().isDouble()) dtypeChgDouble(); else setSignedState(signst); - if (!rangep) { // Set based on keyword properties + if (!rangep && wantwidth) { // Constant width + m_msb = wantwidth - 1; + width(wantwidth, wantwidth); + } else if (!rangep) { // Set based on keyword properties // V3Width will pull from this width if (keyword().width() > 1 && !isOpaque()) rangep = new AstRange(fileline(), keyword().width()-1, 0); width(keyword().width(), keyword().width()); @@ -305,14 +308,22 @@ public: bool isOpaque() const { return keyword().isOpaque(); } bool isSloppy() const { return keyword().isSloppy(); } bool isZeroInit() const { return keyword().isZeroInit(); } - int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); } + bool isRanged() const { return rangep() || m_msb; } + int msb() const { if (!rangep()) return m_msb; 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 msbEndianed() const { if (!rangep()) return m_msb; 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()); } bool implicit() const { return m_implicit; } void implicit(bool flag) { m_implicit = flag; } + void cvtRangeConst() { // Convert to smaller represenation + if (rangep() && rangep()->castConst() && lsb()==0 && !littleEndian()) { + m_msb = msb(); + rangep()->deleteTree(); + rangep(NULL); + } + } }; struct AstConstDType : public AstNodeDType { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 80b2d7c82..ec8870721 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1627,6 +1627,12 @@ private: } } + // Simplify + virtual void visit(AstBasicDType* nodep, AstNUser*) { + nodep->iterateChildren(*this); + nodep->cvtRangeConst(); + } + //----- // Jump elimination diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 110983502..2e29ec776 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -193,7 +193,7 @@ private: const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant if (AstBasicDType* bdtypep = dtypep->castBasicDType()) { - if (bdtypep->rangep()) { + if (bdtypep->isRanged()) { for (int index_docs=bdtypep->lsb(); index_docsmsb()+1; index_docs++) { int index_code = index_docs - bdtypep->lsb(); ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]", diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 458709395..029d79ece 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -453,9 +453,9 @@ void EmitCSyms::emitSymImp() { string bounds; if (AstBasicDType* basicp = varp->basicp()) { // Range is always first, it's not in "C" order - if (basicp->rangep()) { - bounds += " ,"; bounds += cvtToStr(basicp->rangep()->msbConst()); - bounds += ","; bounds += cvtToStr(basicp->rangep()->lsbConst()); + if (basicp->isRanged()) { + bounds += " ,"; bounds += cvtToStr(basicp->msb()); + bounds += ","; bounds += cvtToStr(basicp->lsb()); dim++; } for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) { diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 8a8ba62a5..6217fe8bf 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -486,6 +486,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->isSigned()) putfs(nodep,"signed "); putfs(nodep,nodep->prettyName()); if (nodep->rangep()) { puts(" "); nodep->rangep()->iterateAndNext(*this); puts(" "); } + else if (nodep->msb()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); } } virtual void visit(AstConstDType* nodep, AstNUser*) { putfs(nodep,"const "); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 4ff0f2859..162f63b6c 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -204,6 +204,7 @@ private: AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); AstNode* constzerop; + int m1value = nodep->widthMin()-1; // Constant of width-1; not changing dtype width if (nodep->signedFlavor()) { // Then over shifting gives the sign bit, not all zeros // Note *NOT* clean output -- just like normal shift! @@ -212,7 +213,7 @@ private: new AstShiftR(nodep->fileline(), nodep->lhsp()->cloneTree(false), new AstConst(nodep->fileline(), - nodep->widthMin()-1), + m1value), nodep->width())); } else { V3Number zeronum (nodep->fileline(), nodep->width(), 0); diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 0be0a9b30..79cdde9c9 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -237,6 +237,7 @@ private: = new AstVar (fl, AstVarType::MODULETEMP, "__Vtable" + cvtToStr(m_modTables) +"_"+outvarp->name(), new AstArrayDType (fl, + // FUTURE: If support more types, below can use outvarp->dtype() new AstBasicDType(fl, AstLogicPacked(), outvarp->width()), new AstRange (fl, VL_MASK_I(m_inWidth), 0))); tablevarp->isConst(true); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 901d452c6..eaa99e2ac 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -405,7 +405,7 @@ private: int frommsb = nodep->fromp()->width() - 1; int fromlsb = 0; AstNodeVarRef* varrp = nodep->fromp()->castNodeVarRef(); - if (varrp && varrp->varp()->basicp()->rangep()) { // Selecting a bit from a multibit register + if (varrp && varrp->varp()->basicp()->isRanged()) { // Selecting a bit from a multibit register frommsb = varrp->varp()->basicp()->msbMaxSelect(); // Corrected for negative lsb fromlsb = varrp->varp()->basicp()->lsb(); } diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 1900caa72..d32812ded 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -83,7 +83,7 @@ private: return adtypep; } else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) { - if (!adtypep->rangep()) { + if (!adtypep->isRanged()) { nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<prettyName()); return NULL; } @@ -145,13 +145,13 @@ private: AstVar* varp = varFromBasefrom(basefromp); // SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!) if (!varp->basicp()->rangep()) { - // vector without range is ok, for example a INTEGER x; y = x[21:0]; + // vector without range, or 0 lsb is ok, for example a INTEGER x; y = x[21:0]; return underp; } else { if (!varp->basicp()->rangep()->msbp()->castConst() || !varp->basicp()->rangep()->lsbp()->castConst()) varp->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(varp) - if (varp->basicp()->rangep()->littleEndian()) { + if (varp->basicp()->littleEndian()) { // reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under) AstNode* newp = newSubNeg(varp->basicp()->msb(), underp); return newp; @@ -263,7 +263,7 @@ private: } } else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) { if (adtypep) {} // Unused - if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) { + if (varp->basicp()->littleEndian()) { // Below code assumes big bit endian; just works out if we swap int x = msb; msb = lsb; lsb = x; } @@ -308,7 +308,7 @@ private: if (AstBasicDType* adtypep = ddtypep->castBasicDType()) { AstSel* newp = NULL; if (nodep->castSelPlus()) { - if (adtypep->rangep() && adtypep->rangep()->littleEndian()) { + if (adtypep->littleEndian()) { // SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width) newp = new AstSel (nodep->fileline(), fromp, @@ -322,7 +322,7 @@ private: widthp); } } else if (nodep->castSelMinus()) { - if (adtypep->rangep() && adtypep->rangep()->littleEndian()) { + if (adtypep->littleEndian()) { // SELMINUS(from,msb,width) -> SEL(from, msb-[bit]) newp = new AstSel (nodep->fileline(), fromp, diff --git a/src/verilog.y b/src/verilog.y index c4b3eed98..5782fd4cd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -122,7 +122,7 @@ public: // then [1:1] becomes the basicdtype range; everything else is arraying // the final [5:5][4:4] will be passed in another call to createArray AstRange* rangearraysp = NULL; - if (dtypep->rangep()) { + if (dtypep->isRanged()) { rangearraysp = rangesp; // Already a range; everything is an array } else { AstRange* finalp = rangesp;