Support negative bit indexes.

Allow arbitrary characters in symbols (to make '-' work.)
Final merge from negative_lsb branch.
This commit is contained in:
Wilson Snyder 2008-10-06 09:59:22 -04:00
parent cdd6ea8e60
commit 3b1929259a
18 changed files with 230 additions and 114 deletions

View File

@ -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]

View File

@ -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;

View File

@ -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; }

View File

@ -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 {

View File

@ -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; }

View File

@ -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;

View File

@ -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("+:");

View File

@ -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),

View File

@ -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");
}

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
#######################################################################
#######################################################################