Internals: Move width internals to inside class; move WidthCommit. No functional change
This commit is contained in:
parent
1b3d252bfe
commit
4fa1e45d45
704
src/V3Width.cpp
704
src/V3Width.cpp
|
|
@ -57,6 +57,10 @@
|
|||
#include "V3Const.h"
|
||||
#include "V3Task.h"
|
||||
|
||||
// More code; this file was getting too large; see actions there
|
||||
#define _V3WIDTH_CPP_
|
||||
#include "V3WidthCommit.h"
|
||||
|
||||
//######################################################################
|
||||
// Width state, as a visitor of each AstNode
|
||||
|
||||
|
|
@ -99,19 +103,16 @@ private:
|
|||
// VISITORS
|
||||
// Naming: width_{output size rule}_{lhs rule}_{rhs rule}
|
||||
// Widths: 1 bit out, lhs 1 bit
|
||||
void width_O1_L1(AstNode* nodep, AstNUser* vup);
|
||||
virtual void visit(AstLogNot* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); }
|
||||
virtual void visit(AstPslBool* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); }
|
||||
|
||||
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit
|
||||
void width_O1_L1_R1(AstNode* nodep, AstNUser* vup);
|
||||
virtual void visit(AstLogAnd* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
|
||||
virtual void visit(AstLogOr* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
|
||||
virtual void visit(AstLogIf* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
|
||||
virtual void visit(AstLogIff* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
|
||||
|
||||
// Widths: 1 bit out, Any width lhs
|
||||
void width_O1_L(AstNode* nodep, AstNUser* vup);
|
||||
virtual void visit(AstRedAnd* nodep, AstNUser* vup) { width_O1_L(nodep,vup); }
|
||||
virtual void visit(AstRedOr* nodep, AstNUser* vup) { width_O1_L(nodep,vup); }
|
||||
virtual void visit(AstRedXnor* nodep, AstNUser* vup){ width_O1_L(nodep,vup); }
|
||||
|
|
@ -121,7 +122,6 @@ private:
|
|||
virtual void visit(AstOneHot0* nodep,AstNUser* vup) { width_O1_L(nodep,vup); }
|
||||
|
||||
// Widths: 1 bit out, lhs width == rhs width
|
||||
void width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup);
|
||||
virtual void visit(AstEq* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); }
|
||||
virtual void visit(AstEqCase* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); }
|
||||
virtual void visit(AstEqWild* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); }
|
||||
|
|
@ -138,7 +138,6 @@ private:
|
|||
virtual void visit(AstNeqWild* nodep, AstNUser* vup){ width_O1_L_Rlhs(nodep,vup); }
|
||||
|
||||
// Widths: out width = lhs width = rhs width
|
||||
void width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup);
|
||||
virtual void visit(AstAnd* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||
virtual void visit(AstOr* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||
virtual void visit(AstXnor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||
|
|
@ -156,26 +155,20 @@ private:
|
|||
virtual void visit(AstMulS* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||
|
||||
// Widths: out width = lhs width, but upper matters
|
||||
void width_Olhs_L(AstNodeUniop* nodep, AstNUser* vup);
|
||||
virtual void visit(AstNot* nodep, AstNUser* vup) { width_Olhs_L(nodep,vup); }
|
||||
virtual void visit(AstUnaryMin* nodep, AstNUser* vup) { width_Olhs_L(nodep,vup); }
|
||||
|
||||
// Widths: out width = lhs width, upper doesn't matter
|
||||
void width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* vup);
|
||||
virtual void visit(AstSigned* nodep, AstNUser* vup) { width_Olhs_Lforce(nodep,vup); }
|
||||
virtual void visit(AstUnsigned* nodep, AstNUser* vup) { width_Olhs_Lforce(nodep,vup); }
|
||||
|
||||
// Widths: Output width from lhs, rhs<33 bits
|
||||
void width_Olhs_L_R32(AstNode* nodep, AstNUser* vup);
|
||||
virtual void visit(AstPow* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
|
||||
virtual void visit(AstPowS* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
|
||||
virtual void visit(AstShiftL* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
|
||||
virtual void visit(AstShiftR* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
|
||||
virtual void visit(AstShiftRS* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
|
||||
|
||||
// Widths: Fixed
|
||||
void width_Ofixed_L(AstNodeUniop* nodep, AstNUser* vup, int width);
|
||||
|
||||
// Widths: Constant, terminal
|
||||
virtual void visit(AstTime* nodep, AstNUser*) { nodep->width(64,64); }
|
||||
virtual void visit(AstTestPlusArgs* nodep, AstNUser*) { nodep->width(32,32); }
|
||||
|
|
@ -464,7 +457,7 @@ private:
|
|||
int selwidth = V3Number::log2b(nodep->lhsp()->width())+1;
|
||||
nodep->width(selwidth,selwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCvtPackString* nodep, AstNUser* vup) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
|
|
@ -942,7 +935,7 @@ private:
|
|||
m_funcp = NULL;
|
||||
}
|
||||
virtual void visit(AstReturn* nodep, AstNUser* vup) {
|
||||
if (!m_funcp) {
|
||||
if (!m_funcp) {
|
||||
if (nodep->lhsp()) { // Return w/o value ok other places
|
||||
nodep->v3error("Return with return value isn't underneath a function");
|
||||
}
|
||||
|
|
@ -1047,18 +1040,328 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
bool widthBad (AstNode* nodep, int expWidth, int expWidthMin);
|
||||
//----------------------------------------------------------------------
|
||||
// METHODs
|
||||
|
||||
bool widthBad (AstNode* nodep, int expWidth, int expWidthMin) {
|
||||
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
if (nodep->widthSized() && nodep->width() != expWidthMin) return true;
|
||||
if (!nodep->widthSized() && nodep->widthMin() > expWidthMin) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void fixWidthExtend (AstNode* nodep, int expWidth) {
|
||||
// Fix the width mismatch by extending or truncating bits
|
||||
// Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312;
|
||||
// A(CONSTwide)+B becomes A(CONSTwidened)+B
|
||||
// A(somewide)+B becomes A(TRUNC(somewide,width))+B
|
||||
// or A(EXTRACT(somewide,width,0))+B
|
||||
UINFO(4," widthExtend_old: "<<nodep<<endl);
|
||||
AstConst* constp = nodep->castConst();
|
||||
if (constp && !nodep->isSigned()) {
|
||||
// Save later constant propagation work, just right-size it.
|
||||
V3Number num (nodep->fileline(), expWidth);
|
||||
num.opAssign(constp->num());
|
||||
num.isSigned(nodep->isSigned());
|
||||
AstNode* newp = new AstConst(nodep->fileline(), num);
|
||||
constp->replaceWith(newp);
|
||||
pushDeletep(constp); constp=NULL;
|
||||
nodep=newp;
|
||||
} else if (expWidth<nodep->width()) {
|
||||
// Trunc - Extract
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
|
||||
linker.relink(newp);
|
||||
nodep=newp;
|
||||
} else {
|
||||
// Extend
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = (nodep->isSigned()
|
||||
? (new AstExtendS(nodep->fileline(), nodep))->castNode()
|
||||
: (new AstExtend (nodep->fileline(), nodep))->castNode());
|
||||
linker.relink(newp);
|
||||
nodep=newp;
|
||||
}
|
||||
nodep->width(expWidth,expWidth);
|
||||
UINFO(4," _new: "<<nodep<<endl);
|
||||
}
|
||||
|
||||
void fixWidthReduce (AstNode* nodep, int expWidth) {
|
||||
// Fix the width mismatch by adding a reduction OR operator
|
||||
// IF (A(CONSTwide)) becomes IF (A(CONSTreduced))
|
||||
// IF (A(somewide)) becomes IF (A(REDOR(somewide)))
|
||||
// Attempt to fix it quietly
|
||||
UINFO(4," widthReduce_old: "<<nodep<<endl);
|
||||
AstConst* constp = nodep->castConst();
|
||||
if (constp) {
|
||||
V3Number num (nodep->fileline(), expWidth);
|
||||
num.opRedOr(constp->num());
|
||||
num.isSigned(constp->isSigned());
|
||||
AstNode* newp = new AstConst(nodep->fileline(), num);
|
||||
constp->replaceWith(newp);
|
||||
nodep=newp;
|
||||
} else {
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = new AstRedOr(nodep->fileline(), nodep);
|
||||
linker.relink(newp);
|
||||
nodep=newp;
|
||||
}
|
||||
nodep->width(expWidth,expWidth);
|
||||
UINFO(4," _new: "<<nodep<<endl);
|
||||
}
|
||||
|
||||
bool fixAutoExtend (AstNode*& nodepr, int expWidth) {
|
||||
// For SystemVerilog '0,'1,'x,'z, autoextend and don't warn
|
||||
if (AstConst* constp = nodepr->castConst()) {
|
||||
if (constp->num().autoExtend() && !constp->num().sized() && constp->width()==1) {
|
||||
// Make it the proper size. Careful of proper extension of 0's/1's
|
||||
V3Number num (constp->fileline(), expWidth);
|
||||
num.opRepl(constp->num(), expWidth); // {width{'1}}
|
||||
AstNode* newp = new AstConst(constp->fileline(), num);
|
||||
// Spec says always unsigned with proper width
|
||||
if (debug()>4) constp->dumpTree(cout," fixAutoExtend_old: ");
|
||||
if (debug()>4) newp->dumpTree(cout," _new: ");
|
||||
constp->replaceWith(newp);
|
||||
constp->deleteTree(); constp=NULL;
|
||||
// Tell caller the new constp, and that we changed it.
|
||||
nodepr = newp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // No change
|
||||
}
|
||||
|
||||
void widthCheck (AstNode* nodep, const char* side,
|
||||
AstNode* underp, int expWidth, int expWidthMin,
|
||||
bool ignoreWarn=false);
|
||||
bool ignoreWarn=false) {
|
||||
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e"<<expWidth<<" m"<<expWidthMin<<" i"<<ignoreWarn<<endl);
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
bool bad = widthBad(underp,expWidth,expWidthMin);
|
||||
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
|
||||
if (underp->castConst() && underp->castConst()->num().isFromString()
|
||||
&& expWidth > underp->width()
|
||||
&& (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
|
||||
// reg [31:0] == "foo" we'll consider probably fine.
|
||||
// Maybe this should be a special warning? Not for now.
|
||||
ignoreWarn = true;
|
||||
}
|
||||
if ((nodep->castAdd() && underp->width()==1 && underp->isOne())
|
||||
|| (nodep->castSub() && underp->width()==1 && underp->isOne() && 0==strcmp(side,"RHS"))) {
|
||||
// "foo + 1'b1", or "foo - 1'b1" are very common, people assume they extend correctly
|
||||
ignoreWarn = true;
|
||||
}
|
||||
|
||||
if (bad && !ignoreWarn) {
|
||||
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
|
||||
nodep->v3warn(WIDTH,"Operator "<<nodep->prettyTypeName()
|
||||
<<" expects "<<expWidth
|
||||
<<(expWidth!=expWidthMin?" or "+cvtToStr(expWidthMin):"")
|
||||
<<" bits on the "<<side<<", but "<<side<<"'s "
|
||||
<<underp->prettyTypeName()<<" generates "<<underp->width()
|
||||
<<(underp->width()!=underp->widthMin()
|
||||
?" or "+cvtToStr(underp->widthMin()):"")
|
||||
<<" bits.");
|
||||
}
|
||||
if (bad || underp->width()!=expWidth) {
|
||||
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
|
||||
}
|
||||
}
|
||||
|
||||
void widthCheckReduce (AstNode* nodep, const char* side,
|
||||
AstNode* underp, int expWidth, int expWidthMin,
|
||||
bool ignoreWarn=false);
|
||||
void widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin);
|
||||
bool fixAutoExtend (AstNode*& nodepr, int expWidth);
|
||||
void fixWidthExtend (AstNode* nodep, int expWidth);
|
||||
void fixWidthReduce (AstNode* nodep, int expWidth);
|
||||
bool ignoreWarn=false) {
|
||||
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
if (expWidth!=1) nodep->v3fatalSrc("Only for binary functions");
|
||||
bool bad = widthBad(underp,expWidth,expWidthMin);
|
||||
if (bad) {
|
||||
if (!ignoreWarn) {
|
||||
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
|
||||
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->prettyTypeName()
|
||||
<<" expects 1 bit on the "<<side<<", but "<<side<<"'s "
|
||||
<<underp->prettyTypeName()<<" generates "<<underp->width()
|
||||
<<(underp->width()!=underp->widthMin()
|
||||
?" or "+cvtToStr(underp->widthMin()):"")
|
||||
<<" bits.");
|
||||
}
|
||||
fixWidthReduce(underp, expWidth); underp=NULL;//Changed
|
||||
}
|
||||
}
|
||||
|
||||
void widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin) {
|
||||
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
|
||||
bool bad = widthBad(underp,expWidth,expWidth);
|
||||
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
|
||||
if (bad) {
|
||||
nodep->v3warn(WIDTH,(inputPin?"Input":"Output")
|
||||
<<" port connection "<<nodep->prettyName()
|
||||
<<" expects "<<expWidth
|
||||
<<" bits but connection's "
|
||||
<<underp->prettyTypeName()<<" generates "<<underp->width()
|
||||
<<(underp->width()!=underp->widthMin()
|
||||
?" or "+cvtToStr(underp->widthMin()):"")
|
||||
<<" bits.");
|
||||
}
|
||||
// We only fix input mismatches
|
||||
if (bad && inputPin) {
|
||||
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
|
||||
}
|
||||
}
|
||||
|
||||
void width_O1_L1(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, lhs 1 bit
|
||||
// We calculate the width of the UNDER expression.
|
||||
// We then check its width to see if it's legal, and edit if not
|
||||
// We finally set the width of our output
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
|
||||
}
|
||||
nodep->width(1,1);
|
||||
if (vup->c()->final()) {
|
||||
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
|
||||
}
|
||||
}
|
||||
|
||||
void width_O1_L1_R1(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
|
||||
}
|
||||
nodep->width(1,1);
|
||||
if (vup->c()->final()) {
|
||||
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
|
||||
widthCheckReduce(nodep,"RHS",nodep->op2p(),1,1);
|
||||
}
|
||||
}
|
||||
|
||||
void width_O1_L(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, Any width lhs
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
nodep->width(1,1);
|
||||
}
|
||||
|
||||
void width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, lhs width == rhs width
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = max(nodep->op1p()->width(), nodep->op2p()->width());
|
||||
int ewidth = max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin());
|
||||
nodep->width(1,1);
|
||||
if (vup->c()->final()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
|
||||
widthCheck(nodep,"RHS",nodep->op2p(),width,ewidth);
|
||||
}
|
||||
}
|
||||
|
||||
void width_Ofixed_L(AstNodeUniop* nodep, AstNUser* vup, int width) {
|
||||
// Widths: out width = specified width
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
nodep->width(width,width);
|
||||
}
|
||||
|
||||
void width_Olhs_L(AstNodeUniop* nodep, AstNUser* vup) {
|
||||
// Widths: out width = lhs width
|
||||
// "Interim results shall take the max of operands, including LHS of assignments"
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = max(vup->c()->width(), nodep->lhsp()->width());
|
||||
int ewidth = max(vup->c()->widthMin(), nodep->lhsp()->widthMin());
|
||||
nodep->width(width,ewidth);
|
||||
if (vup->c()->final()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
|
||||
}
|
||||
}
|
||||
|
||||
void width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* vup) {
|
||||
// Widths: out width = lhs width
|
||||
// It always comes exactly from LHS; ignores any upper operand
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = nodep->lhsp()->width();
|
||||
int ewidth = nodep->lhsp()->width(); // Not minWidth; force it.
|
||||
nodep->width(width,ewidth);
|
||||
if (vup->c()->final()) {
|
||||
// Final call, so make sure children check their sizes
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
|
||||
}
|
||||
}
|
||||
|
||||
void width_Olhs_L_R32(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: Output width from lhs, rhs<33 bits
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
int width = max(vup->c()->width(), nodep->op1p()->width());
|
||||
int ewidth = max(vup->c()->widthMin(), nodep->op1p()->widthMin());
|
||||
nodep->width(width,ewidth);
|
||||
if (vup->c()->final()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
|
||||
if (nodep->op2p()->width()>32)
|
||||
nodep->op2p()->v3error("Unsupported: Shifting of by a over 32 bit number isn't supported."
|
||||
<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
||||
}
|
||||
}
|
||||
|
||||
void width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: out width = lhs width = rhs width
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
// If errors are off, we need to follow the spec; thus we really need to do the max()
|
||||
// because the rhs could be larger, and we need to have proper editing to get the widths
|
||||
// to be the same for our operations.
|
||||
if (vup->c()->prelim()) { // First stage evaluation
|
||||
// Determine expression widths only relying on what's in the subops
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = max(vup->c()->width(), max(nodep->op1p()->width(), nodep->op2p()->width()));
|
||||
int mwidth = max(vup->c()->widthMin(), max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin()));
|
||||
nodep->width(width,mwidth);
|
||||
if (vup->c()->final()) {
|
||||
// Final call, so make sure children check their sizes
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
|
||||
// Some warning suppressions
|
||||
bool lhsOk=false; bool rhsOk = false;
|
||||
if (nodep->castAdd() || nodep->castSub()) {
|
||||
lhsOk = (mwidth == (nodep->op1p()->widthMin()+1)); // Ok if user wants extra bit from carry
|
||||
rhsOk = (mwidth == (nodep->op2p()->widthMin()+1)); // Ok if user wants extra bit from carry
|
||||
} else if (nodep->castMul() || nodep->castMulS()) {
|
||||
lhsOk = (mwidth >= (nodep->op1p()->widthMin()));
|
||||
rhsOk = (mwidth >= (nodep->op2p()->widthMin()));
|
||||
}
|
||||
// Error report and change sizes for suboperands of this node.
|
||||
widthCheck(nodep,"LHS",nodep->op1p(),width,mwidth,lhsOk);
|
||||
widthCheck(nodep,"RHS",nodep->op2p(),width,mwidth,rhsOk);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
|
|
@ -1075,365 +1378,6 @@ public:
|
|||
virtual ~WidthVisitor() {}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// METHODs
|
||||
|
||||
bool WidthVisitor::widthBad (AstNode* nodep, int expWidth, int expWidthMin) {
|
||||
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
if (nodep->widthSized() && nodep->width() != expWidthMin) return true;
|
||||
if (!nodep->widthSized() && nodep->widthMin() > expWidthMin) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void WidthVisitor::fixWidthExtend (AstNode* nodep, int expWidth) {
|
||||
// Fix the width mismatch by extending or truncating bits
|
||||
// Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312;
|
||||
// A(CONSTwide)+B becomes A(CONSTwidened)+B
|
||||
// A(somewide)+B becomes A(TRUNC(somewide,width))+B
|
||||
// or A(EXTRACT(somewide,width,0))+B
|
||||
UINFO(4," widthExtend_old: "<<nodep<<endl);
|
||||
AstConst* constp = nodep->castConst();
|
||||
if (constp && !nodep->isSigned()) {
|
||||
// Save later constant propagation work, just right-size it.
|
||||
V3Number num (nodep->fileline(), expWidth);
|
||||
num.opAssign(constp->num());
|
||||
num.isSigned(nodep->isSigned());
|
||||
AstNode* newp = new AstConst(nodep->fileline(), num);
|
||||
constp->replaceWith(newp);
|
||||
pushDeletep(constp); constp=NULL;
|
||||
nodep=newp;
|
||||
} else if (expWidth<nodep->width()) {
|
||||
// Trunc - Extract
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
|
||||
linker.relink(newp);
|
||||
nodep=newp;
|
||||
} else {
|
||||
// Extend
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = (nodep->isSigned()
|
||||
? (new AstExtendS(nodep->fileline(), nodep))->castNode()
|
||||
: (new AstExtend (nodep->fileline(), nodep))->castNode());
|
||||
linker.relink(newp);
|
||||
nodep=newp;
|
||||
}
|
||||
nodep->width(expWidth,expWidth);
|
||||
UINFO(4," _new: "<<nodep<<endl);
|
||||
}
|
||||
|
||||
void WidthVisitor::fixWidthReduce (AstNode* nodep, int expWidth) {
|
||||
// Fix the width mismatch by adding a reduction OR operator
|
||||
// IF (A(CONSTwide)) becomes IF (A(CONSTreduced))
|
||||
// IF (A(somewide)) becomes IF (A(REDOR(somewide)))
|
||||
// Attempt to fix it quietly
|
||||
UINFO(4," widthReduce_old: "<<nodep<<endl);
|
||||
AstConst* constp = nodep->castConst();
|
||||
if (constp) {
|
||||
V3Number num (nodep->fileline(), expWidth);
|
||||
num.opRedOr(constp->num());
|
||||
num.isSigned(constp->isSigned());
|
||||
AstNode* newp = new AstConst(nodep->fileline(), num);
|
||||
constp->replaceWith(newp);
|
||||
nodep=newp;
|
||||
} else {
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
AstNode* newp = new AstRedOr(nodep->fileline(), nodep);
|
||||
linker.relink(newp);
|
||||
nodep=newp;
|
||||
}
|
||||
nodep->width(expWidth,expWidth);
|
||||
UINFO(4," _new: "<<nodep<<endl);
|
||||
}
|
||||
|
||||
bool WidthVisitor::fixAutoExtend (AstNode*& nodepr, int expWidth) {
|
||||
// For SystemVerilog '0,'1,'x,'z, autoextend and don't warn
|
||||
if (AstConst* constp = nodepr->castConst()) {
|
||||
if (constp->num().autoExtend() && !constp->num().sized() && constp->width()==1) {
|
||||
// Make it the proper size. Careful of proper extension of 0's/1's
|
||||
V3Number num (constp->fileline(), expWidth);
|
||||
num.opRepl(constp->num(), expWidth); // {width{'1}}
|
||||
AstNode* newp = new AstConst(constp->fileline(), num);
|
||||
// Spec says always unsigned with proper width
|
||||
if (debug()>4) constp->dumpTree(cout," fixAutoExtend_old: ");
|
||||
if (debug()>4) newp->dumpTree(cout," _new: ");
|
||||
constp->replaceWith(newp);
|
||||
constp->deleteTree(); constp=NULL;
|
||||
// Tell caller the new constp, and that we changed it.
|
||||
nodepr = newp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // No change
|
||||
}
|
||||
|
||||
void WidthVisitor::widthCheck (AstNode* nodep, const char* side,
|
||||
AstNode* underp, int expWidth, int expWidthMin,
|
||||
bool ignoreWarn) {
|
||||
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e"<<expWidth<<" m"<<expWidthMin<<" i"<<ignoreWarn<<endl);
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
bool bad = widthBad(underp,expWidth,expWidthMin);
|
||||
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
|
||||
if (underp->castConst() && underp->castConst()->num().isFromString()
|
||||
&& expWidth > underp->width()
|
||||
&& (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
|
||||
// reg [31:0] == "foo" we'll consider probably fine.
|
||||
// Maybe this should be a special warning? Not for now.
|
||||
ignoreWarn = true;
|
||||
}
|
||||
if ((nodep->castAdd() && underp->width()==1 && underp->isOne())
|
||||
|| (nodep->castSub() && underp->width()==1 && underp->isOne() && 0==strcmp(side,"RHS"))) {
|
||||
// "foo + 1'b1", or "foo - 1'b1" are very common, people assume they extend correctly
|
||||
ignoreWarn = true;
|
||||
}
|
||||
|
||||
if (bad && !ignoreWarn) {
|
||||
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
|
||||
nodep->v3warn(WIDTH,"Operator "<<nodep->prettyTypeName()
|
||||
<<" expects "<<expWidth
|
||||
<<(expWidth!=expWidthMin?" or "+cvtToStr(expWidthMin):"")
|
||||
<<" bits on the "<<side<<", but "<<side<<"'s "
|
||||
<<underp->prettyTypeName()<<" generates "<<underp->width()
|
||||
<<(underp->width()!=underp->widthMin()
|
||||
?" or "+cvtToStr(underp->widthMin()):"")
|
||||
<<" bits.");
|
||||
}
|
||||
if (bad || underp->width()!=expWidth) {
|
||||
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::widthCheckReduce (AstNode* nodep, const char* side,
|
||||
AstNode* underp, int expWidth, int expWidthMin,
|
||||
bool ignoreWarn) {
|
||||
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
|
||||
if (expWidthMin==0) expWidthMin = expWidth;
|
||||
if (expWidth!=1) nodep->v3fatalSrc("Only for binary functions");
|
||||
bool bad = widthBad(underp,expWidth,expWidthMin);
|
||||
if (bad) {
|
||||
if (!ignoreWarn) {
|
||||
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
|
||||
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->prettyTypeName()
|
||||
<<" expects 1 bit on the "<<side<<", but "<<side<<"'s "
|
||||
<<underp->prettyTypeName()<<" generates "<<underp->width()
|
||||
<<(underp->width()!=underp->widthMin()
|
||||
?" or "+cvtToStr(underp->widthMin()):"")
|
||||
<<" bits.");
|
||||
}
|
||||
fixWidthReduce(underp, expWidth); underp=NULL;//Changed
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin) {
|
||||
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
|
||||
bool bad = widthBad(underp,expWidth,expWidth);
|
||||
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
|
||||
if (bad) {
|
||||
nodep->v3warn(WIDTH,(inputPin?"Input":"Output")
|
||||
<<" port connection "<<nodep->prettyName()
|
||||
<<" expects "<<expWidth
|
||||
<<" bits but connection's "
|
||||
<<underp->prettyTypeName()<<" generates "<<underp->width()
|
||||
<<(underp->width()!=underp->widthMin()
|
||||
?" or "+cvtToStr(underp->widthMin()):"")
|
||||
<<" bits.");
|
||||
}
|
||||
// We only fix input mismatches
|
||||
if (bad && inputPin) {
|
||||
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_O1_L1(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, lhs 1 bit
|
||||
// We calculate the width of the UNDER expression.
|
||||
// We then check its width to see if it's legal, and edit if not
|
||||
// We finally set the width of our output
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
|
||||
}
|
||||
nodep->width(1,1);
|
||||
if (vup->c()->final()) {
|
||||
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_O1_L1_R1(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
|
||||
}
|
||||
nodep->width(1,1);
|
||||
if (vup->c()->final()) {
|
||||
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
|
||||
widthCheckReduce(nodep,"RHS",nodep->op2p(),1,1);
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_O1_L(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, Any width lhs
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
nodep->width(1,1);
|
||||
}
|
||||
|
||||
void WidthVisitor::width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: 1 bit out, lhs width == rhs width
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = max(nodep->op1p()->width(), nodep->op2p()->width());
|
||||
int ewidth = max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin());
|
||||
nodep->width(1,1);
|
||||
if (vup->c()->final()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
|
||||
widthCheck(nodep,"RHS",nodep->op2p(),width,ewidth);
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_Ofixed_L(AstNodeUniop* nodep, AstNUser* vup, int width) {
|
||||
// Widths: out width = specified width
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
nodep->width(width,width);
|
||||
}
|
||||
|
||||
void WidthVisitor::width_Olhs_L(AstNodeUniop* nodep, AstNUser* vup) {
|
||||
// Widths: out width = lhs width
|
||||
// "Interim results shall take the max of operands, including LHS of assignments"
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = max(vup->c()->width(), nodep->lhsp()->width());
|
||||
int ewidth = max(vup->c()->widthMin(), nodep->lhsp()->widthMin());
|
||||
nodep->width(width,ewidth);
|
||||
if (vup->c()->final()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* vup) {
|
||||
// Widths: out width = lhs width
|
||||
// It always comes exactly from LHS; ignores any upper operand
|
||||
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = nodep->lhsp()->width();
|
||||
int ewidth = nodep->lhsp()->width(); // Not minWidth; force it.
|
||||
nodep->width(width,ewidth);
|
||||
if (vup->c()->final()) {
|
||||
// Final call, so make sure children check their sizes
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_Olhs_L_R32(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: Output width from lhs, rhs<33 bits
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
if (vup->c()->prelim()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
int width = max(vup->c()->width(), nodep->op1p()->width());
|
||||
int ewidth = max(vup->c()->widthMin(), nodep->op1p()->widthMin());
|
||||
nodep->width(width,ewidth);
|
||||
if (vup->c()->final()) {
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
|
||||
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
|
||||
if (nodep->op2p()->width()>32)
|
||||
nodep->op2p()->v3error("Unsupported: Shifting of by a over 32 bit number isn't supported."
|
||||
<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
||||
}
|
||||
}
|
||||
|
||||
void WidthVisitor::width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup) {
|
||||
// Widths: out width = lhs width = rhs width
|
||||
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
|
||||
// If errors are off, we need to follow the spec; thus we really need to do the max()
|
||||
// because the rhs could be larger, and we need to have proper editing to get the widths
|
||||
// to be the same for our operations.
|
||||
if (vup->c()->prelim()) { // First stage evaluation
|
||||
// Determine expression widths only relying on what's in the subops
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
}
|
||||
int width = max(vup->c()->width(), max(nodep->op1p()->width(), nodep->op2p()->width()));
|
||||
int mwidth = max(vup->c()->widthMin(), max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin()));
|
||||
nodep->width(width,mwidth);
|
||||
if (vup->c()->final()) {
|
||||
// Final call, so make sure children check their sizes
|
||||
nodep->op1p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
|
||||
nodep->op2p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
|
||||
// Some warning suppressions
|
||||
bool lhsOk=false; bool rhsOk = false;
|
||||
if (nodep->castAdd() || nodep->castSub()) {
|
||||
lhsOk = (mwidth == (nodep->op1p()->widthMin()+1)); // Ok if user wants extra bit from carry
|
||||
rhsOk = (mwidth == (nodep->op2p()->widthMin()+1)); // Ok if user wants extra bit from carry
|
||||
} else if (nodep->castMul() || nodep->castMulS()) {
|
||||
lhsOk = (mwidth >= (nodep->op1p()->widthMin()));
|
||||
rhsOk = (mwidth >= (nodep->op2p()->widthMin()));
|
||||
}
|
||||
// Error report and change sizes for suboperands of this node.
|
||||
widthCheck(nodep,"LHS",nodep->op1p(),width,mwidth,lhsOk);
|
||||
widthCheck(nodep,"RHS",nodep->op2p(),width,mwidth,rhsOk);
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class WidthCommitVisitor : public AstNVisitor {
|
||||
// Now that all widthing is complete,
|
||||
// Copy all width() to widthMin(). V3Const expects this
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||
nodep->width(nodep->width(),nodep->width());
|
||||
if ((nodep->width() != nodep->num().width()) || !nodep->num().sized()) {
|
||||
V3Number num (nodep->fileline(), nodep->width());
|
||||
num.opAssign(nodep->num());
|
||||
num.isSigned(nodep->isSigned());
|
||||
AstNode* newp = new AstConst(nodep->fileline(), num);
|
||||
nodep->replaceWith(newp);
|
||||
//if (debug()>4) nodep->dumpTree(cout," fixConstSize_old: ");
|
||||
//if (debug()>4) newp->dumpTree(cout," _new: ");
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->width(nodep->width(),nodep->width());
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
// This check could go anywhere after V3Param
|
||||
nodep->v3fatalSrc("Presels should have been removed before this point");
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
WidthCommitVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~WidthCommitVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Width class functions
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Cleanup stage in V3Width
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3WIDTHCOMMIT_H_
|
||||
#define _V3WIDTHCOMMIT_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
#ifndef _V3WIDTH_CPP_
|
||||
# error "V3WidthCommit for V3Width internal use only"
|
||||
#endif
|
||||
|
||||
//######################################################################
|
||||
|
||||
class WidthCommitVisitor : public AstNVisitor {
|
||||
// Now that all widthing is complete,
|
||||
// Copy all width() to widthMin(). V3Const expects this
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||
nodep->width(nodep->width(),nodep->width());
|
||||
if ((nodep->width() != nodep->num().width()) || !nodep->num().sized()) {
|
||||
V3Number num (nodep->fileline(), nodep->width());
|
||||
num.opAssign(nodep->num());
|
||||
num.isSigned(nodep->isSigned());
|
||||
AstNode* newp = new AstConst(nodep->fileline(), num);
|
||||
nodep->replaceWith(newp);
|
||||
//if (debug()>4) nodep->dumpTree(cout," fixConstSize_old: ");
|
||||
//if (debug()>4) newp->dumpTree(cout," _new: ");
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->width(nodep->width(),nodep->width());
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
// This check could go anywhere after V3Param
|
||||
nodep->v3fatalSrc("Presels should have been removed before this point");
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
WidthCommitVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~WidthCommitVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // Guard
|
||||
Loading…
Reference in New Issue