From 3b1929259ad9f60cfe2d531399dbbc43fd3875d4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Oct 2008 09:59:22 -0400 Subject: [PATCH] Support negative bit indexes. Allow arbitrary characters in symbols (to make '-' work.) Final merge from negative_lsb branch. --- Changes | 3 + src/V3Ast.cpp | 8 +++ src/V3Ast.h | 1 + src/V3AstNodes.cpp | 2 +- src/V3AstNodes.h | 29 ++++---- src/V3Const.cpp | 31 +++++---- src/V3EmitV.cpp | 6 +- src/V3Expand.cpp | 4 +- src/V3LinkParse.cpp | 3 +- src/V3LinkResolve.cpp | 2 +- src/V3Number.cpp | 14 ++-- src/V3Number.h | 1 - src/V3Unroll.cpp | 22 ++++--- src/V3Width.cpp | 10 +-- test_regress/t/t_trace_public.v | 17 +++++ test_regress/t/t_trace_public_func.out | 50 +++++++++----- test_regress/t/t_trace_public_sig.out | 50 +++++++++----- test_verilated/vgen.pl | 91 ++++++++++++++++++-------- 18 files changed, 230 insertions(+), 114 deletions(-) diff --git a/Changes b/Changes index cda7ce9b7..178c9ec87 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,9 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.67** +** Support negative bit indexes. [Stephane Laurent] + Tracing negative indexes requires latest Verilog-Perl and SystemPerl. + *** Suppress width warnings between constant strings and wider vectors. [Rodney Sinclair] diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 3c16fed10..542821a77 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -111,6 +111,14 @@ string AstNode::encodeName(const string& namein) { return out; } +string AstNode::encodeNumber(vlsint64_t num) { + if (num < 0) { + return "__2D"+cvtToStr(-num); // 2D=- + } else { + return cvtToStr(num); + } +} + string AstNode::shortName() const { string pretty = name(); string::size_type pos; diff --git a/src/V3Ast.h b/src/V3Ast.h index 9580b80eb..d1d851ad6 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -579,6 +579,7 @@ public: static string dedotName(const string& namein); // Name with dots removed static string prettyName(const string& namein); // Name for printing out to the user static string encodeName(const string& namein); // Encode user name into internal C representation + static string encodeNumber(vlsint64_t numin); // Encode number into internal C representation string prettyName() const { return prettyName(name()); } FileLine* fileline() const { return m_fileline; } int width() const { return m_width; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d7f96941e..ee73e5264 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -43,7 +43,7 @@ void AstNodeVarRef::cloneRelink() { } int AstNodeSel::bitConst() const { - AstConst* constp=bitp()->castConst(); return (constp?constp->asInt():0); + AstConst* constp=bitp()->castConst(); return (constp?constp->toSInt():0); } bool AstVar::isSigPublic() const { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 5fb4bcb06..02dd7924b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -50,8 +50,8 @@ public: virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } virtual string name() const { return num().ascii(); } // * = Value virtual const V3Number& num() const { return m_num; } // * = Value - uint32_t asInt() const { return num().asInt(); } // Old, should be removed uint32_t toUInt() const { return num().toUInt(); } + vlsint32_t toSInt() const { return num().toSInt(); } vluint64_t toUQuad() const { return num().toUQuad(); } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { V3ERROR_NA; return ""; } @@ -79,8 +79,8 @@ struct AstRange : public AstNode { AstRange* cloneTree(bool cloneNextLink) { return AstNode::cloneTree(cloneNextLink)->castRange(); } AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression - int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->asInt():0); } - int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->asInt():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 elementsConst() const { return msbConst()-lsbConst()+1; } virtual string emitC() { V3ERROR_NA; return ""; } virtual V3Hash sameHash() const { return V3Hash(); } @@ -193,7 +193,7 @@ struct AstSel : public AstNodeTriop { // Children: varref|arraysel, math, constant math AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) :AstNodeTriop(fl, fromp, lsbp, widthp) { - if (widthp->castConst()) width(widthp->castConst()->asInt(), widthp->castConst()->asInt()); + if (widthp->castConst()) width(widthp->castConst()->toUInt(), widthp->castConst()->toUInt()); } AstSel(FileLine* fl, AstNode* fromp, int lsbp, int bitwidth) :AstNodeTriop(fl, fromp, @@ -205,7 +205,7 @@ struct AstSel : public AstNodeTriop { virtual AstNode* clone() { return new AstSel(*this); } virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) { - out.opRange(from, bit.asInt()+width.asInt()-1, bit.asInt()); } + out.opRange(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); } virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially virtual string emitC() { return this->widthp()->isOne() @@ -222,9 +222,9 @@ struct AstSel : public AstNodeTriop { AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing) AstNode* lsbp() const { return op2p()->castNode(); } // op2 = Msb selection expression AstNode* widthp() const { return op3p()->castNode(); } // op3 = Width - uint32_t lsbConst() const { return lsbp()->castConst()->asInt(); } - uint32_t widthConst() const { return widthp()->castConst()->toUInt(); } - uint32_t msbConst() const { return lsbConst()+widthConst()-1; } + int widthConst() const { return widthp()->castConst()->toSInt(); } + int lsbConst() const { return lsbp()->castConst()->toSInt(); } + int msbConst() const { return lsbConst()+widthConst()-1; } }; struct AstVar : public AstNode { @@ -363,8 +363,9 @@ public: bool attrIsolateAssign() const { return m_attrIsolateAssign; } int widthAlignBytes() const; // Structure alignment 1,2,4 or 8 bytes (arrays affect this) int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,... - uint32_t msb() const { if (!rangep()) return 0; return rangep()->msbConst(); } - uint32_t lsb() const { if (!rangep()) return 0; return rangep()->lsbConst(); } + int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); } + int lsb() const { if (!rangep()) return 0; return rangep()->lsbConst(); } + int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index uint32_t arrayElements() const; // 1, or total multiplication of all dimensions virtual string verilogKwd() const; void propagateAttrFrom(AstVar* fromp) { @@ -1694,8 +1695,8 @@ struct AstTraceDecl : public AstNodeStmt { private: string m_showname; // Name of variable uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines - uint32_t m_lsb; // Property of var the trace details - uint32_t m_msb; // Property of var the trace details + int m_lsb; // Property of var the trace details + int m_msb; // Property of var the trace details uint32_t m_arrayLsb; // Property of var the trace details uint32_t m_arrayMsb; // Property of var the trace details uint32_t m_codeInc; // Code increment @@ -1723,8 +1724,8 @@ public: uint32_t code() const { return m_code; } void code(uint32_t code) { m_code=code; } uint32_t codeInc() const { return m_codeInc; } - uint32_t msb() const { return m_msb; } - uint32_t lsb() const { return m_lsb; } + int msb() const { return m_msb; } + int lsb() const { return m_lsb; } uint32_t arrayMsb() const { return m_arrayMsb; } uint32_t arrayLsb() const { return m_arrayLsb; } uint32_t arrayWidth() const { if (!arrayMsb()) return 0; return arrayMsb()-arrayLsb()+1; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 0d417a1c0..11ea66fdf 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -134,11 +134,11 @@ private: } bool operandHugeShiftL(AstNodeBiop* nodep) { return (nodep->rhsp()->castConst() - && nodep->rhsp()->castConst()->asInt() >= (uint32_t)(nodep->width())); + && nodep->rhsp()->castConst()->toUInt() >= (uint32_t)(nodep->width())); } bool operandHugeShiftR(AstNodeBiop* nodep) { return (nodep->rhsp()->castConst() - && nodep->rhsp()->castConst()->asInt() >= (uint32_t)(nodep->lhsp()->width())); + && nodep->rhsp()->castConst()->toUInt() >= (uint32_t)(nodep->lhsp()->width())); } bool operandIsTwo(AstNode* nodep) { return (nodep->castConst() @@ -215,15 +215,18 @@ private: bool warnSelect(AstSel* nodep) { AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp()); if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { + AstVar* varp = varrefp->varp(); if (m_warn && nodep->lsbp()->castConst() && nodep->widthp()->castConst() - && (!varrefp->varp()->rangep() || varrefp->varp()->msb()) // else it's non-resolvable parameterized - && ( ( (nodep->msbConst() > varrefp->varp()->msb()) - || (nodep->lsbConst() > varrefp->varp()->msb())))) { + && (!varp->rangep() || varp->msb()) // else it's non-resolvable parameterized + && ( ( (nodep->msbConst() > varp->msbMaxSelect()) + || (nodep->lsbConst() > varp->msbMaxSelect())))) { nodep->v3error("Selection index out of range: " <msbConst()<<":"<lsbConst() - <<" outside "<varp()->msb()<<":0"); + <<" outside "<msbMaxSelect()<<":0" + <<(varp->lsb()>=0 ? "" + :" (adjusted +"+cvtToStr(-varp->lsb())+" to account for negative lsb)")); } } return false; // Not a transform, so NOP @@ -432,8 +435,8 @@ private: nodep->accept(*this); // Further reduce, either node may have more reductions. } else { // We know shift amounts are constant, but might be a mixed left/right shift - int shift1 = shift1p->castConst()->asInt(); if (lhsp->castShiftR()) shift1=-shift1; - int shift2 = shift2p->castConst()->asInt(); if (nodep->castShiftR()) shift2=-shift2; + int shift1 = shift1p->castConst()->toUInt(); if (lhsp->castShiftR()) shift1=-shift1; + int shift2 = shift2p->castConst()->toUInt(); if (nodep->castShiftR()) shift2=-shift2; int newshift = shift1+shift2; shift1p->deleteTree(); shift1p=NULL; shift2p->deleteTree(); shift1p=NULL; @@ -490,9 +493,9 @@ private: if (!varNotReferenced(nodep->rhsp(), varref1p->varp())) return false; if (!varNotReferenced(nextp->rhsp(), varref2p->varp())) return false; // Swap? - if (( con1p->asInt() != con2p->asInt() + sel2p->width()) - &&(con2p->asInt() != con1p->asInt() + sel1p->width())) return false; - bool lsbFirstAssign = (con1p->asInt() < con2p->asInt()); + if (( con1p->toSInt() != con2p->toSInt() + sel2p->width()) + &&(con2p->toSInt() != con1p->toSInt() + sel1p->width())) return false; + bool lsbFirstAssign = (con1p->toUInt() < con2p->toUInt()); // If the user already has nice 32-bit divisions, keep them to aid later subdivision //if (VL_BITBIT_I(con1p->toUInt()) == 0) return false; UINFO(4,"replaceAssignMultiSel "<castAnd()->rhsp()->castShiftR()) return false; AstShiftR* shiftp = nodep->castAnd()->rhsp()->castShiftR(); if (!shiftp->rhsp()->castConst()) return false; - if ((uint32_t)(nodep->width()) <= shiftp->rhsp()->castConst()->asInt()) return false; + if ((uint32_t)(nodep->width()) <= shiftp->rhsp()->castConst()->toUInt()) return false; return true; } void replaceBoolShift(AstNode* nodep) { @@ -784,7 +787,7 @@ private: AstNode* newlsbp; if (lsb1p->castConst() && lsb2p->castConst()) { newlsbp = new AstConst(lsb1p->fileline(), - lsb1p->castConst()->asInt() + lsb2p->castConst()->asInt()); + lsb1p->castConst()->toUInt() + lsb2p->castConst()->toUInt()); lsb1p->deleteTree(); lsb1p=NULL; lsb2p->deleteTree(); lsb2p=NULL; } else { @@ -851,7 +854,7 @@ private: AstNode* widthp = nodep->widthp()->unlinkFrBack(); AstSel* newp = new AstSel(nodep->fileline(), fromp, - new AstConst(lsbp->fileline(), lsbp->asInt() % fromp->width()), + new AstConst(lsbp->fileline(), lsbp->toUInt() % fromp->width()), widthp); newp->widthSignedFrom(nodep); nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 42b046277..ae5c9625a 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -362,11 +362,11 @@ public: if (nodep->widthp()->isOne()) { nodep->lsbp()->iterateAndNext(*this); } else { - puts(cvtToStr(nodep->lsbp()->castConst()->asInt() - +nodep->widthp()->castConst()->asInt() + puts(cvtToStr(nodep->lsbp()->castConst()->toSInt() + +nodep->widthp()->castConst()->toSInt() -1)); puts(":"); - nodep->lsbp()->iterateAndNext(*this); + puts(cvtToStr(nodep->lsbp()->castConst()->toSInt())); } } else { nodep->lsbp()->iterateAndNext(*this); puts("+:"); diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 0e945c5c1..85fa041bc 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -172,7 +172,7 @@ private: // Return equation to get the VL_BITWORD of a constant or non-constant if (lsbp->castConst()) { return new AstConst (lsbp->fileline(), - wordAdder + VL_BITWORD_I(lsbp->castConst()->asInt())); + wordAdder + VL_BITWORD_I(lsbp->castConst()->toUInt())); } else { AstNode* shiftp = new AstShiftR (lsbp->fileline(), lsbp->cloneTree(true), @@ -203,7 +203,7 @@ private: // Return equation to get the VL_BITBIT of a constant or non-constant if (lsbp->castConst()) { return new AstConst (lsbp->fileline(), - VL_BITBIT_I(lsbp->castConst()->asInt())); + VL_BITBIT_I(lsbp->castConst()->toUInt())); } else { return new AstAnd (lsbp->fileline(), new AstConst(lsbp->fileline(), VL_WORDSIZE-1), diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index b13969da3..18b0daf8e 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -160,7 +160,8 @@ private: m_dotText = ""; nodep->lhsp()->iterateAndNext(*this); if (AstConst* constp = nodep->rhsp()->castConst()) { - m_dotText = m_dotText+"__BRA__"+cvtToStr(constp->asInt())+"__KET__"; + string index = AstNode::encodeNumber(constp->toSInt()); + m_dotText = m_dotText+"__BRA__"+index+"__KET__"; } else { nodep->v3error("Unsupported: Non-constant inside []'s in the cell part of a dotted reference"); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 85750d6e8..528588465 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -223,7 +223,7 @@ private: AstNode* widthp; if (msbp->castConst() && lsbp->castConst()) { // Quite common, save V3Const some effort - V3Number widnum (msbp->fileline(),32,msbp->castConst()->asInt() +1-lsbp->castConst()->asInt()); + 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); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index ec24b2fee..bd356a9d4 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -470,10 +470,16 @@ uint32_t V3Number::toUInt() const { } vlsint32_t V3Number::toSInt() const { - uint32_t v = toUInt(); - uint32_t signExtend = (-(v & (1UL<<(width()-1)))); - uint32_t extended = v | signExtend; - return (vlsint32_t)(extended); + if (isSigned()) { + uint32_t v = toUInt(); + uint32_t signExtend = (-(v & (1UL<<(width()-1)))); + uint32_t extended = v | signExtend; + return (vlsint32_t)(extended); + } else { + // Where we use this (widths, etc) and care about signedness, + // we can reasonably assume the MSB isn't set on unsigned numbers. + return (vlsint32_t)toUInt(); + } } vluint64_t V3Number::toUQuad() const { diff --git a/src/V3Number.h b/src/V3Number.h index 65323bc47..81d6acba2 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -137,7 +137,6 @@ public: void width(int width, bool sized=true); void isSigned(bool ssigned) { m_signed=ssigned; } bool isUnknown() const; - uint32_t asInt() const { return toUInt(); } // Deprecated, use toUInt/toSInt uint32_t toUInt() const; vlsint32_t toSInt() const; vluint64_t toUQuad() const; diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 1da01c14e..85838a359 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -76,6 +76,11 @@ private: return false; } + int unrollCount() { + return m_generate ? v3Global.opt.unrollCount()*16 + : v3Global.opt.unrollCount(); + } + bool forUnrollCheck(AstNode* nodep, AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp) AstNode* precondsp, AstNode* condp, @@ -158,16 +163,16 @@ private: || constStopp->width()>32 || constStopp->num().isFourState() || constIncp->width()>32 || constIncp->num().isFourState()) return cantUnroll(nodep, "init/final/increment too large or four state"); - vlsint32_t valInit = constInitp->num().toUInt(); // Extract as unsigned, then make signed - vlsint32_t valStop = constStopp->num().toUInt(); // Extract as unsigned, then make signed + vlsint32_t valInit = constInitp->num().toSInt(); + vlsint32_t valStop = constStopp->num().toSInt(); if (lte) valStop++; if (gte) valStop--; vlsint32_t valInc = constIncp->num().toSInt(); if (subtract) valInc = -valInc; UINFO(8," In Numbers: for (v="< v3Global.opt.unrollCount()*3) { - nodep->v3error("Loop unrolling took too long; probably this is an infinite loop."); + if (++times > unrollCount()*3) { + nodep->v3error("Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "<asInt())+"__DOT__"+nodep->name(); + string index = AstNode::encodeNumber(m_varValuep->toSInt()); + string nname = (string)"genfor"+index+"__DOT__"+nodep->name(); // Verilog seems to drop the for loop name and tack on [#] - nname = nodep->name() + "__BRA__" + cvtToStr(m_varValuep->asInt()) + "__KET__"; + nname = nodep->name() + "__BRA__" + index + "__KET__"; //UINFO(8," Rename begin "<name(nname); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 011dd5ae1..b1aebb36f 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -238,9 +238,9 @@ private: if (!lsbConstp) nodep->v3error("LSB of bit range isn't a constant"); nodep->width(1,1); return; } - uint32_t msb = msbConstp->asInt(); - uint32_t lsb = lsbConstp->asInt(); - if (msb > (1UL<<28)) nodep->v3error("MSB of bit range is huge; vector of over 1billion bits: 0x"<toSInt(); + int lsb = lsbConstp->toSInt(); + if (msb > (1<<28)) nodep->v3error("MSB of bit range is huge; vector of over 1billion bits: 0x"<fromp()->castNodeVarRef(); if (varrp && varrp->varp()->rangep()) { // Selecting a bit from a multibit register - frommsb = varrp->varp()->msb(); + frommsb = varrp->varp()->msbMaxSelect(); // Corrected for negative lsb fromlsb = varrp->varp()->lsb(); } int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit @@ -332,6 +332,8 @@ private: frommsb = varrp->varp()->arrayp(dimension)->msbConst(); fromlsb = varrp->varp()->arrayp(dimension)->lsbConst(); if (fromlsb>frommsb) {int t=frommsb; frommsb=fromlsb; fromlsb=t; } + // However, if the lsb<0 we may go negative, so need more bits! + if (fromlsb < 0) frommsb += -fromlsb; nodep->width(outwidth,outwidth); // Width out = width of array } int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit diff --git a/test_regress/t/t_trace_public.v b/test_regress/t/t_trace_public.v index f4ae67e89..5f340fc57 100644 --- a/test_regress/t/t_trace_public.v +++ b/test_regress/t/t_trace_public.v @@ -8,6 +8,7 @@ module t ( output reg RESET ); + neg neg (.clk(CLK)); glbl glbl; initial RESET = 1'b1; @@ -28,3 +29,19 @@ module glbl(); wire GSR /*verilator public*/; `endif endmodule + +module neg ( + input clk + ); + + reg [0:-7] i8; initial i8 = '0; + reg [-1:-48] i48; initial i48 = '0; + reg [63:-64] i128; initial i128 = '0; + + always @ (posedge clk) begin + i8 <= ~i8; + i48 <= ~i48; + i128 <= ~i128; + end + +endmodule diff --git a/test_regress/t/t_trace_public_func.out b/test_regress/t/t_trace_public_func.out index 8b7f25407..39f95e8db 100644 --- a/test_regress/t/t_trace_public_func.out +++ b/test_regress/t/t_trace_public_func.out @@ -1,16 +1,22 @@ $version Generated by SpTraceVcd $end -$date Wed Jun 11 19:43:32 2008 +$date Thu Sep 18 07:54:41 2008 $end $timescale 1ns $end $scope module TOP $end - $var wire 1 $ CLK $end - $var wire 1 % RESET $end + $var wire 1 , CLK $end + $var wire 1 - RESET $end $scope module v $end - $var wire 1 $ CLK $end + $var wire 1 , CLK $end $var wire 1 # RESET $end $scope module glbl $end - $var wire 1 & GSR $end + $var wire 1 + GSR $end + $upscope $end + $scope module neg $end + $var wire 1 , clk $end + $var wire 128 ' i128 [63:-64] $end + $var wire 48 % i48 [-1:-48] $end + $var wire 8 $ i8 [0:-7] $end $upscope $end $upscope $end $upscope $end @@ -19,35 +25,47 @@ $enddefinitions $end #0 1# -0$ -1% -1& +b00000000 $ +b000000000000000000000000000000000000000000000000 % +b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ' +1+ +1- +0, #1 #2 #3 -1$ +b11111111 $ +b111111111111111111111111111111111111111111111111 % +b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 ' +1, #4 #5 #6 -0$ +0, #7 -0& +0+ #8 #9 0# -1$ -0% +b00000000 $ +b000000000000000000000000000000000000000000000000 % +b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ' +0- +1, #10 #11 #12 -0$ +0, #13 #14 #15 -1$ +b11111111 $ +b111111111111111111111111111111111111111111111111 % +b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 ' +1, #16 #17 #18 -0$ +0, #19 #20 diff --git a/test_regress/t/t_trace_public_sig.out b/test_regress/t/t_trace_public_sig.out index 8b7f25407..3b29842cb 100644 --- a/test_regress/t/t_trace_public_sig.out +++ b/test_regress/t/t_trace_public_sig.out @@ -1,16 +1,22 @@ $version Generated by SpTraceVcd $end -$date Wed Jun 11 19:43:32 2008 +$date Thu Sep 18 07:55:56 2008 $end $timescale 1ns $end $scope module TOP $end - $var wire 1 $ CLK $end - $var wire 1 % RESET $end + $var wire 1 + CLK $end + $var wire 1 , RESET $end $scope module v $end - $var wire 1 $ CLK $end + $var wire 1 + CLK $end $var wire 1 # RESET $end $scope module glbl $end - $var wire 1 & GSR $end + $var wire 1 - GSR $end + $upscope $end + $scope module neg $end + $var wire 1 + clk $end + $var wire 128 ' i128 [63:-64] $end + $var wire 48 % i48 [-1:-48] $end + $var wire 8 $ i8 [0:-7] $end $upscope $end $upscope $end $upscope $end @@ -19,35 +25,47 @@ $enddefinitions $end #0 1# -0$ -1% -1& +b00000000 $ +b000000000000000000000000000000000000000000000000 % +b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ' +1, +0+ +1- #1 #2 #3 -1$ +b11111111 $ +b111111111111111111111111111111111111111111111111 % +b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 ' +1+ #4 #5 #6 -0$ +0+ #7 -0& +0- #8 #9 0# -1$ -0% +b00000000 $ +b000000000000000000000000000000000000000000000000 % +b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ' +0, +1+ #10 #11 #12 -0$ +0+ #13 #14 #15 -1$ +b11111111 $ +b111111111111111111111111111111111111111111111111 % +b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 ' +1+ #16 #17 #18 -0$ +0+ #19 #20 diff --git a/test_verilated/vgen.pl b/test_verilated/vgen.pl index 350b6f00f..029e8c2c3 100755 --- a/test_verilated/vgen.pl +++ b/test_verilated/vgen.pl @@ -28,6 +28,7 @@ our $Rerun_Args = $0." ".join(' ',@Orig_ARGV); use vars qw (@Blocks %Vars + %VarAttrs %VarsBlock %Tree @Commit @@ -40,6 +41,7 @@ use vars qw (@Blocks # width=> Number of bits the output size is, 0=you tell me. # func=> What to put in output file # signed=> 0=unsigned output, 1=signed output, '%1'=signed if op1 signed +# lsb=> LSB for variable declarations # em=> How to calculate emulated return value # %w Width of this output op ($treeref->{width}) # %v Output value ($treeref->{val}) @@ -118,13 +120,31 @@ my %ops2 = ( 'VCONST'=> {pl=>'', rnd=>'rnd_const(%tr);'}, 'VIDNEW'=> {pl=>'%tv=$Vars{%i}{val};', - rnd=>'%i=next_id(%tw); $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg); id_commit(%tr,"%i");1;',}, + rnd=>'%i=next_id(%tw);' + .' $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg);' + .' $VarAttrs{%i}{lsb} = rnd_lsb();' + .' id_commit(%tr,"%i");1;',}, 'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_old(%tr);', ok_id_width=>1,}, 'VIDSAME'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_same(%tr);', ok_id_width=>1,}, - 'VRANGE'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1; %2r=val_leaf($msb); %3r=val_leaf($lsb); $Vars{%i}=gen_leaf(width=>($msb+1));'}, - 'VBITSEL'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%2v);', rnd=>'%i=next_id(%tw); my $wid=min(128,rnd_width()|3); %2r=gen_leaf(width=>(log2($wid)-1),signed=>0); $Vars{%i}=gen_leaf(width=>$wid);'}, - 'VBITSELP'=> {pl=>'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0)); $Vars{%i}=gen_leaf(width=>$wid);'}, - 'VBITSELM'=> {pl=>'VBITSELM(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-1; my $minval=%tw-1; %2r=val_leaf(rnd($maxval-$minval)+$minval); $Vars{%i}=gen_leaf(width=>$wid);'}, # No easy way to make expr with specified minimum + # These create IDs they then extract from + 'VRANGE'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});', + rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' + .' my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1;' + .' %2r=val_leaf($msb); %3r=val_leaf($lsb);' + .' $Vars{%i}=gen_leaf(width=>($msb+1));'}, + 'VBITSEL'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%2v,$VarAttrs{%i}{lsb});', + rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' + .' my $wid=min(128,rnd_width()|3);' + .' %2r=gen_leaf(width=>(log2($wid)-1),signed=>0);' + .' $Vars{%i}=gen_leaf(width=>$wid);'}, + 'VBITSELP'=> {pl=>'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});', + rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' + .' my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0));' + .' $Vars{%i}=gen_leaf(width=>$wid);'}, + 'VBITSELM'=> {pl=>'VBITSELM(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});', + rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' + .' my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-1; my $minval=%tw-1; %2r=val_leaf(rnd($maxval-$minval)+$minval);' + .' $Vars{%i}=gen_leaf(width=>$wid);'}, # No easy way to make expr with specified minimum # Unary 'VEXTEND'=> {pl=>'VRESIZE (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>rnd_width(%tw-1));'}, 'VLOGNOT'=> {pl=>'VLOGNOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, @@ -388,6 +408,11 @@ sub rnd_int { return rnd32(); } +sub rnd_lsb { + return 0; + #return rnd(8)-4; # Not working yet +} + sub rnd { return (int(rand($_[0]))) if ($_[0] < (1<<15)); return (rnd32() % $_[0]); @@ -818,12 +843,14 @@ sub decl_text { return sprintf " %s<%s> %s; //=%s" , $decl_with, $type, $var, $varref->{val}->to_Hex; } else { - return sprintf " reg %s [%3d:0] %s %s; //=%s" + return sprintf " reg %s [%3d:%3d] %s %s; //=%d'h%s" , ($varref->{signed}?"signed":" ") - , ($varref->{val}->Size)-1, + , ($varref->{val}->Size)-1+$VarAttrs{$var}{lsb}, + , $VarAttrs{$var}{lsb} , $var , (rnd(100)<30 ? "/*verilator public*/":(" "x length("/*verilator public*/"))) - , $varref->{val}->to_Hex; + , $varref->{val}->Size + , lc $varref->{val}->to_Hex; } } @@ -948,29 +975,35 @@ sub VPOW { # Power is a signed operation print "VV = $o\n"; } sub VRANGE { #print "RANGE ",$_[1]->to_Hex,' ',$_[2]->to_Hex,' ',$_[3]->to_Hex," \n"; - return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0),$_[3]->Word_Read(0)); } + return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0),$_[3]->Word_Read(0), $_[4]); } sub VBITSELP { - return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0)+$_[3]->Word_Read(0)-1, $_[2]->Word_Read(0)); } + return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0)+$_[3]->Word_Read(0)-1, $_[2]->Word_Read(0), $_[4]); } sub VBITSELM { - return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0), $_[2]->Word_Read(0)-$_[3]->Word_Read(0)+1); } -sub VRANGE_CONST { #print "RANGE ",$_[1]->to_Hex,' ',$_[2],' ',$_[3]," \n"; - my $size = $_[2] - $_[3] + 1; - my $o=Bit::Vector->new($size); - if ($_[3] < $_[1]->Size) { - $o->Interval_Copy($_[1],0,$_[3],$size); - } - $_[0]{val}=$o; } -sub VCONCAT { my $o=Bit::Vector->new($_[1]->Size + $_[2]->Size); - $o->Interval_Copy($_[1],$_[2]->Size,0,$_[1]->Size); - $o->Interval_Copy($_[2],0,0,$_[2]->Size); - $_[0]{val}=$o; } -sub VREPLIC { my $o=Bit::Vector->new($_[1]->Word_Read(0) * $_[2]->Size); - my $pos = 0; - for (my $time=0; $time<($_[1]->Word_Read(0)); $time++) { - $o->Interval_Copy($_[2],$pos,0,$_[2]->Size); - $pos += $_[2]->Size; - } - $_[0]{val}=$o; } + return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0), $_[2]->Word_Read(0)-$_[3]->Word_Read(0)+1, $_[4]); } +sub VRANGE_CONST { + # to, from, msb, lsb, variable_lsb_to_subtract + #print "RANGE ",$_[1]->to_Hex,' ',$_[2],' ',$_[3],' ',$_[4]," \n"; + my $size = $_[2] - $_[3] + 1; + my $o=Bit::Vector->new($size); + if ($_[3] < $_[1]->Size) { + $o->Interval_Copy($_[1],0,$_[3]-$_[4],$size); + } + $_[0]{val}=$o; } +sub VCONCAT { + my $o=Bit::Vector->new($_[1]->Size + $_[2]->Size); + $o->Interval_Copy($_[1],$_[2]->Size,0,$_[1]->Size); + $o->Interval_Copy($_[2],0,0,$_[2]->Size); + $_[0]{val}=$o; +} +sub VREPLIC { + my $o=Bit::Vector->new($_[1]->Word_Read(0) * $_[2]->Size); + my $pos = 0; + for (my $time=0; $time<($_[1]->Word_Read(0)); $time++) { + $o->Interval_Copy($_[2],$pos,0,$_[2]->Size); + $pos += $_[2]->Size; + } + $_[0]{val}=$o; +} ####################################################################### #######################################################################