Support negative bit indexes.
Allow arbitrary characters in symbols (to make '-' work.) Final merge from negative_lsb branch.
This commit is contained in:
parent
cdd6ea8e60
commit
3b1929259a
3
Changes
3
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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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: "
|
||||
<<nodep->msbConst()<<":"<<nodep->lsbConst()
|
||||
<<" outside "<<varrefp->varp()->msb()<<":0");
|
||||
<<" outside "<<varp->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 "<<nodep<<endl);
|
||||
|
|
@ -648,7 +651,7 @@ private:
|
|||
if (!nodep->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;
|
||||
|
|
|
|||
|
|
@ -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("+:");
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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="<<valInit<<"; v<"<<valStop<<"; v=v+"<<valInc<<")\n");
|
||||
//
|
||||
if (!m_generate) {
|
||||
UINFO(8, " ~Iters: "<<((valStop - valInit)/valInc)<<" c="<<v3Global.opt.unrollCount()<<endl);
|
||||
if (((valStop - valInit)/valInc) > v3Global.opt.unrollCount())
|
||||
UINFO(8, " ~Iters: "<<((valStop - valInit)/valInc)<<" c="<<unrollCount()<<endl);
|
||||
if (((valStop - valInit)/valInc) > unrollCount())
|
||||
return cantUnroll(nodep, "too many iterations");
|
||||
|
||||
// Less than 10 statements in the body?
|
||||
|
|
@ -253,8 +258,8 @@ private:
|
|||
else newbodysp = oneloopp;
|
||||
|
||||
m_statIters++;
|
||||
if (++times > 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 "<<unrollCount());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -347,9 +352,10 @@ private:
|
|||
) {
|
||||
// Rename it, as otherwise we may get a conflict
|
||||
// V3Begin sees these DOTs and makes CellInlines for us.
|
||||
string nname = (string)"genfor"+cvtToStr(m_varValuep->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 "<<nname<<" "<<nodep<<endl);
|
||||
nodep->name(nname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"<<hex<<msb);
|
||||
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.
|
||||
|
|
@ -296,7 +296,7 @@ private:
|
|||
int fromlsb = 0;
|
||||
AstNodeVarRef* varrp = nodep->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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
|
|
|
|||
Loading…
Reference in New Issue