Internals: Move array definitions to AstArrayDType instead of under AstVars.
Prep work for more complicated data types.
This commit is contained in:
parent
db2c6820ee
commit
700c1f836d
|
|
@ -62,6 +62,7 @@ sub diff_dir {
|
|||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{b} = $fn;
|
||||
}
|
||||
my $any;
|
||||
foreach my $base (sort (keys %files)) {
|
||||
my $a = $files{$base}{a};
|
||||
my $b = $files{$base}{b};
|
||||
|
|
@ -70,6 +71,7 @@ sub diff_dir {
|
|||
print "= $a <-> $b\n";
|
||||
diff_file($a,$b);
|
||||
}
|
||||
$any or warn "%Warning: No .tree files found\n";
|
||||
}
|
||||
|
||||
sub diff_file {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
// Things like:
|
||||
// class V3AstNode;
|
||||
|
||||
// Hint class so we can choose constructors
|
||||
class AstLogicPacked {};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstType {
|
||||
|
|
@ -1184,7 +1187,9 @@ struct AstNodeDType : public AstNode {
|
|||
AstNodeDType(FileLine* fl) : AstNode(fl) {}
|
||||
ASTNODE_BASE_FUNCS(NodeDType)
|
||||
// Accessors
|
||||
AstRange* rangep();
|
||||
virtual AstBasicDType* basicp() = 0; // (Slow) recurse down to find basic data type
|
||||
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
};
|
||||
|
||||
struct AstNodeSel : public AstNodeBiop {
|
||||
|
|
|
|||
|
|
@ -35,11 +35,6 @@
|
|||
//======================================================================
|
||||
// Special methods
|
||||
|
||||
AstRange* AstNodeDType::rangep() {
|
||||
if (castBasicDType()) return castBasicDType()->rangep();
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
// We need these here, because the classes they point to aren't defined when we declare the class
|
||||
bool AstNodeVarRef::broken() const { return ((m_varScopep && !m_varScopep->brokeExists())
|
||||
|| (m_varp && !m_varp->brokeExists())); }
|
||||
|
|
@ -52,6 +47,20 @@ int AstNodeSel::bitConst() const {
|
|||
AstConst* constp=bitp()->castConst(); return (constp?constp->toSInt():0);
|
||||
}
|
||||
|
||||
int AstBasicDType::widthAlignBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isQuad()) return 8;
|
||||
else return 4;
|
||||
}
|
||||
|
||||
int AstBasicDType::widthTotalBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isQuad()) return 8;
|
||||
else return widthWords()*(VL_WORDSIZE/8);
|
||||
}
|
||||
|
||||
bool AstVar::isSigPublic() const {
|
||||
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
|
||||
}
|
||||
|
|
@ -77,20 +86,6 @@ void AstVar::combineType(AstVarType type) {
|
|||
m_tristate = true;
|
||||
}
|
||||
|
||||
int AstVar::widthAlignBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isSc() ? isScQuad() : isQuad()) return 8;
|
||||
else return 4;
|
||||
}
|
||||
|
||||
int AstVar::widthTotalBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isSc() ? isScQuad() : isQuad()) return 8;
|
||||
else return widthWords()*(VL_WORDSIZE/8);
|
||||
}
|
||||
|
||||
string AstVar::verilogKwd() const {
|
||||
if (isInout()) {
|
||||
return "inout";
|
||||
|
|
@ -137,32 +132,61 @@ string AstVar::scType() const {
|
|||
}
|
||||
}
|
||||
|
||||
AstRange* AstVar::arrayp(int dimension) const {
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
if ((dimension--)==0) return arrayp;
|
||||
AstNodeDType* AstVar::dtypeDimensionp(int dimension) const {
|
||||
// dimension passed from AstArraySel::dimension
|
||||
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
|
||||
// which is the lowest in the dtype list.
|
||||
// ref order: a[1][2][3][4]
|
||||
// Created as: reg [4] a [1][2][3];
|
||||
// *or* reg a [1][2][3][4];
|
||||
// // The bit select is optional; used only if "leftover" []'s
|
||||
// SEL: SEL4(SEL3(SEL2(SEL1(VARREF0 a))))
|
||||
// DECL: VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (DT RANGE3))))
|
||||
// *or* VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (ARRAYSEL3 (DT))))
|
||||
// SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0
|
||||
int dim = 0;
|
||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
if ((dim++)==dimension) {
|
||||
return dtypep;
|
||||
}
|
||||
dtypep = adtypep->dtypep();
|
||||
continue;
|
||||
} else if (AstBasicDType* adtypep = dtypep->castBasicDType()) {
|
||||
// AstBasicDType - nothing below, return null
|
||||
if (adtypep->rangep()) {
|
||||
if ((dim++) == dimension) {
|
||||
return adtypep;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// Node no ->next in loop; use continue where necessary
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AstVar::arrayDimensions() const {
|
||||
int entries=0;
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
entries++;
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
uint32_t AstVar::arrayElements() const {
|
||||
uint32_t entries=1;
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
entries *= arrayp->elementsConst();
|
||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
entries *= adtypep->elementsConst();
|
||||
dtypep = adtypep->dtypep();
|
||||
} else {
|
||||
// AstBasicDType - nothing below, 1
|
||||
break;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
// Special operators
|
||||
int AstArraySel::dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
|
||||
// Only called after V3Param; so only ArraySel's need to be recursed
|
||||
int AstArraySel::dimension(AstNode* nodep) {
|
||||
// How many dimensions is this reference from the base variable?
|
||||
// nodep is typically the fromp() of a select; thus the first select
|
||||
// is selecting from the entire variable type - effectively dimension 0.
|
||||
// Dimension passed to AstVar::dtypeDimensionp; see comments there
|
||||
int dim = 0;
|
||||
while (nodep) {
|
||||
if (nodep->castNodeSel()) { dim++; nodep=nodep->castNodeSel()->fromp(); continue; }
|
||||
|
|
|
|||
|
|
@ -105,6 +105,31 @@ public:
|
|||
virtual bool same(AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
//==== Data Types
|
||||
|
||||
struct AstArrayDType : public AstNodeDType {
|
||||
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep)
|
||||
: AstNodeDType(fl) {
|
||||
setOp1p(dtypep);
|
||||
setOp2p(rangep);
|
||||
widthSignedFrom(dtypep);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
|
||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstRange* arrayp() const { return op2p()->castRange(); } // op2 = Array(s) of variable
|
||||
void arrayp(AstRange* nodep) { setOp2p(nodep); }
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
|
||||
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return elementsConst() * dtypep()->widthTotalBytes(); }
|
||||
int msb() const { return arrayp()->msbConst(); }
|
||||
int lsb() const { return arrayp()->lsbConst(); }
|
||||
int elementsConst() const { return arrayp()->elementsConst(); }
|
||||
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
|
||||
};
|
||||
|
||||
struct AstBasicDType : public AstNodeDType {
|
||||
// Builtin atomic/vectored data type
|
||||
private:
|
||||
|
|
@ -112,11 +137,17 @@ private:
|
|||
bool m_implicit; // Implicitly declared
|
||||
public:
|
||||
AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstRange* rangep=NULL, AstSignedState signst=signedst_NOP)
|
||||
: AstNodeDType(fl), m_keyword(kwd) {
|
||||
init(signst, rangep);
|
||||
: AstNodeDType(fl) {
|
||||
init(kwd, signst, rangep);
|
||||
}
|
||||
AstBasicDType(FileLine* fl, AstLogicPacked, int wantwidth)
|
||||
: AstNodeDType(fl) {
|
||||
init(AstBasicDTypeKwd::LOGIC, signedst_NOP,
|
||||
((wantwidth > 1) ? new AstRange(fl, wantwidth-1, 0) : NULL));
|
||||
}
|
||||
private:
|
||||
void init(AstSignedState signst, AstRange* rangep) {
|
||||
void init(AstBasicDTypeKwd kwd, AstSignedState signst, AstRange* rangep) {
|
||||
m_keyword = kwd;
|
||||
// Implicitness: // "parameter X" is implicit and sized from initial value, "parameter reg x" not
|
||||
m_implicit = false;
|
||||
if (keyword()==AstBasicDTypeKwd::LOGIC_IMPLICIT) {
|
||||
|
|
@ -148,6 +179,9 @@ public:
|
|||
if (signst!=signedst_NOP) isSigned(signst==signedst_SIGNED);
|
||||
}
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() { return this; } // (Slow) recurse down to find basic data type
|
||||
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||
bool isSloppy() const { return keyword().isSloppy(); }
|
||||
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
||||
|
|
@ -159,6 +193,8 @@ public:
|
|||
bool implicit() const { return m_implicit; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
struct AstArraySel : public AstNodeSel {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
|
|
@ -319,21 +355,19 @@ private:
|
|||
m_trace=false;
|
||||
}
|
||||
public:
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtypep, AstRange* arrayp=NULL)
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtypep)
|
||||
:AstNode(fl)
|
||||
, m_name(name) {
|
||||
init();
|
||||
combineType(type); setOp1p(dtypep); addNOp2p(arrayp);
|
||||
combineType(type); setOp1p(dtypep);
|
||||
width(msb()-lsb()+1,0);
|
||||
}
|
||||
class LogicPacked {};
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, LogicPacked, int wantwidth)
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstLogicPacked, int wantwidth)
|
||||
:AstNode(fl)
|
||||
, m_name(name) {
|
||||
init();
|
||||
combineType(type);
|
||||
setOp1p(new AstBasicDType(fl, AstBasicDTypeKwd::LOGIC,
|
||||
((wantwidth > 1) ? new AstRange(fl, wantwidth-1, 0) : NULL)));
|
||||
setOp1p(new AstBasicDType(fl, AstLogicPacked(), wantwidth));
|
||||
width(wantwidth,0);
|
||||
}
|
||||
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
|
||||
|
|
@ -344,9 +378,6 @@ public:
|
|||
if (examplep->dtypep()) {
|
||||
setOp1p(examplep->dtypep()->cloneTree(true));
|
||||
}
|
||||
if (examplep->arraysp()) {
|
||||
setOp2p(examplep->arraysp()->cloneTree(true));
|
||||
}
|
||||
width(examplep->width(), examplep->widthMin());
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Var, VAR)
|
||||
|
|
@ -361,9 +392,7 @@ public:
|
|||
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
|
||||
void combineType(AstVarType type);
|
||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
AstRange* arraysp() const { return op2p()->castRange(); } // op2 = Array(s) of variable
|
||||
void addArraysp(AstNode* nodep) { addNOp2p(nodep); }
|
||||
AstRange* arrayp(int dim) const; // op2 = Range for specific dimension #
|
||||
AstNodeDType* dtypeDimensionp(int depth) const;
|
||||
AstNode* initp() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
|
||||
void initp(AstNode* nodep) { setOp3p(nodep); }
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
|
|
@ -387,6 +416,7 @@ public:
|
|||
void funcReturn(bool flag) { m_funcReturn = flag; }
|
||||
void trace(bool flag) { m_trace=flag; }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
bool isInput() const { return m_input; }
|
||||
bool isOutput() const { return m_output; }
|
||||
|
|
@ -411,7 +441,7 @@ public:
|
|||
bool isParam() const { return (varType()==AstVarType::LPARAM || varType()==AstVarType::GPARAM); }
|
||||
bool isGParam() const { return (varType()==AstVarType::GPARAM); }
|
||||
bool isGenVar() const { return (varType()==AstVarType::GENVAR); }
|
||||
bool isBitLogic() const { return dtypep()->castBasicDType() && dtypep()->castBasicDType()->isBitLogic(); }
|
||||
bool isBitLogic() const { AstBasicDType* bdtypep = basicp(); return bdtypep && bdtypep->isBitLogic(); }
|
||||
bool isUsedClock() const { return m_usedClock; }
|
||||
bool isUsedParam() const { return m_usedParam; }
|
||||
bool isSc() const { return m_sc; }
|
||||
|
|
@ -429,15 +459,11 @@ public:
|
|||
bool attrFileDescr() const { return m_fileDescr; }
|
||||
bool attrScClocked() const { return m_scClocked; }
|
||||
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,...
|
||||
int msb() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->msb(); }
|
||||
int lsb() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->lsb(); }
|
||||
int msbEndianed() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->msbEndianed(); }
|
||||
int lsbEndianed() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->lsbEndianed(); }
|
||||
int msbMaxSelect() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->msbMaxSelect(); }
|
||||
bool littleEndian() const { return (dtypep() && dtypep()->castBasicDType()->littleEndian()); }
|
||||
int arrayDimensions() const;
|
||||
int msb() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->msb() : 0; }
|
||||
int lsb() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->lsb() : 0; }
|
||||
int msbEndianed() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->msbEndianed() : 0; }
|
||||
int lsbEndianed() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->lsbEndianed() : 0; }
|
||||
int msbMaxSelect() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->msbMaxSelect() : 0; }
|
||||
uint32_t arrayElements() const; // 1, or total multiplication of all dimensions
|
||||
virtual string verilogKwd() const;
|
||||
void propagateAttrFrom(AstVar* fromp) {
|
||||
|
|
@ -1695,8 +1721,13 @@ public:
|
|||
m_code = 0;
|
||||
m_codeInc = varp->arrayElements() * varp->widthWords();
|
||||
m_lsb = varp->lsbEndianed(); m_msb = varp->msbEndianed();
|
||||
m_arrayLsb = varp->arrayp(0) ? varp->arrayp(0)->lsbConst() : 0;
|
||||
m_arrayMsb = varp->arrayp(0) ? varp->arrayp(0)->msbConst() : 0;
|
||||
if (AstArrayDType* adtypep = varp->dtypep()->castArrayDType()) {
|
||||
m_arrayLsb = adtypep->arrayp()->lsbConst();
|
||||
m_arrayMsb = adtypep->arrayp()->msbConst();
|
||||
} else {
|
||||
m_arrayLsb = 0;
|
||||
m_arrayMsb = 0;
|
||||
}
|
||||
}
|
||||
virtual int instrCount() const { return 100; } // Large...
|
||||
ASTNODE_NODE_FUNCS(TraceDecl, TRACEDECL)
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ private:
|
|||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, AstVar::LogicPacked(), countp->width());
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), countp->width());
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
countp);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ private:
|
|||
#endif
|
||||
AstVar* varp = vscp->varp();
|
||||
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
|
||||
if (varp->arraysp()) {
|
||||
if (!varp->dtypep()->castBasicDType()) {
|
||||
vscp->v3error("Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
|
||||
} else {
|
||||
string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ private:
|
|||
}
|
||||
void computeCppWidth (AstNode* nodep) {
|
||||
if (!nodep->user2()) {
|
||||
if (nodep->castVar()) { // Don't want to change variable widths!
|
||||
if (nodep->castVar() || nodep->castNodeDType()) { // Don't want to change variable widths!
|
||||
setCppWidth(nodep, nodep->width(), nodep->width()); // set widthMin anyways so can see it later
|
||||
} else {
|
||||
setCppWidth(nodep, cppWidth(nodep), nodep->widthMin());
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ private:
|
|||
AstVar* varp = vscp->varp();
|
||||
if (varp->width()!=1) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
|
||||
string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName());
|
||||
AstVar* newvarp = new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, AstVar::LogicPacked(), 1);
|
||||
AstVar* newvarp = new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, AstLogicPacked(), 1);
|
||||
newvarp->width(1,1);
|
||||
m_modp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
|
||||
|
|
@ -104,7 +104,7 @@ private:
|
|||
AstVarScope* getCreateLocalVar(FileLine* fl, const string& name, AstVar* examplep, int width) {
|
||||
AstVar* newvarp;
|
||||
if (width) {
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, AstVar::LogicPacked(), width);
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, AstLogicPacked(), width);
|
||||
} else {
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, examplep); // No range; 1 bit.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,14 +306,14 @@ private:
|
|||
|
||||
// Extraction checks
|
||||
bool warnSelect(AstSel* nodep) {
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
|
||||
AstVar* varp = varrefp->varp();
|
||||
if (!varp->dtypep()) varp->v3fatalSrc("Data type lost");
|
||||
if (m_warn
|
||||
&& nodep->lsbp()->castConst()
|
||||
&& nodep->widthp()->castConst()
|
||||
&& (!varp->dtypep()->rangep() || varp->msb())) { // else it's non-resolvable parameterized
|
||||
&& (!varp->basicp()->rangep() || varp->msb())) { // else it's non-resolvable parameterized
|
||||
if (nodep->lsbp()->castConst()->num().isFourState()
|
||||
|| nodep->widthp()->castConst()->num().isFourState()) {
|
||||
nodep->v3error("Selection index is constantly unknown or tristated: "
|
||||
|
|
@ -771,9 +771,9 @@ private:
|
|||
string name1 = ((string)"__Vconcswap"+cvtToStr(m_modp->varNumGetInc()));
|
||||
string name2 = ((string)"__Vconcswap"+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1,
|
||||
AstVar::LogicPacked(), msb1-lsb1+1);
|
||||
AstLogicPacked(), msb1-lsb1+1);
|
||||
AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2,
|
||||
AstVar::LogicPacked(), msb2-lsb2+1);
|
||||
AstLogicPacked(), msb2-lsb2+1);
|
||||
m_modp->addStmtp(temp1p);
|
||||
m_modp->addStmtp(temp2p);
|
||||
AstNodeAssign* asn1ap=nodep->cloneType
|
||||
|
|
|
|||
|
|
@ -48,6 +48,19 @@ private:
|
|||
// TYPES
|
||||
typedef map<string,int> FileMap;
|
||||
|
||||
struct ToggleEnt {
|
||||
string m_comment; // Comment for coverage dump
|
||||
AstNode* m_varRefp; // How to get to this element
|
||||
AstNode* m_chgRefp; // How to get to this element
|
||||
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
|
||||
: m_comment(comment), m_varRefp(vp), m_chgRefp(cp) {}
|
||||
~ToggleEnt() {}
|
||||
void cleanup() {
|
||||
m_varRefp->deleteTree(); m_varRefp=NULL;
|
||||
m_chgRefp->deleteTree(); m_chgRefp=NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// STATE
|
||||
bool m_checkBlock; // Should this block get covered?
|
||||
AstModule* m_modp; // Current module to add statement to
|
||||
|
|
@ -143,12 +156,6 @@ private:
|
|||
// Convert to "AstCoverInc(CoverInc...)"
|
||||
// We'll do this, and make the if(...) coverinc later.
|
||||
|
||||
// Compute size of the problem
|
||||
int dimensions = 0;
|
||||
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
dimensions++;
|
||||
}
|
||||
|
||||
// Add signal to hold the old value
|
||||
string newvarname = (string)"__Vtogcov__"+nodep->shortName();
|
||||
AstVar* chgVarp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
|
||||
|
|
@ -157,61 +164,65 @@ private:
|
|||
// Create bucket for each dimension * bit.
|
||||
// This is necessarily an O(n^2) expansion, which is why
|
||||
// we limit coverage to signals with < 256 bits.
|
||||
vector<int> selects_docs; selects_docs.resize(dimensions);
|
||||
vector<int> selects_code; selects_code.resize(dimensions);
|
||||
toggleVarRecurse(nodep, chgVarp, nodep->arraysp(),
|
||||
0, selects_docs, selects_code );
|
||||
|
||||
ToggleEnt newvec (string(""),
|
||||
new AstVarRef(nodep->fileline(), nodep, false),
|
||||
new AstVarRef(nodep->fileline(), chgVarp, true));
|
||||
toggleVarRecurse(nodep->dtypep(), 0, newvec,
|
||||
nodep, chgVarp);
|
||||
newvec.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void toggleVarRecurse(AstVar* nodep, AstVar* chgVarp, AstRange* arrayp,
|
||||
int dimension, vector<int>& selects_docs, vector<int>& selects_code) {
|
||||
if (arrayp) {
|
||||
for (int index=arrayp->lsbConst(); index<=arrayp->msbConst()+1; index++) {
|
||||
// Handle the next dimension, if any
|
||||
selects_docs[dimension] = index;
|
||||
selects_code[dimension] = index - arrayp->lsbConst();
|
||||
toggleVarRecurse(nodep, chgVarp, arrayp->nextp()->castRange(),
|
||||
dimension+1, selects_docs, selects_code);
|
||||
}
|
||||
} else { // No more arraying - just each bit in the width
|
||||
if (nodep->msb() != nodep->lsb()) {
|
||||
for (int bitindex_docs=nodep->lsb(); bitindex_docs<nodep->msb()+1; bitindex_docs++) {
|
||||
toggleVarBottom(nodep, chgVarp,
|
||||
dimension, selects_docs, selects_code,
|
||||
true, bitindex_docs);
|
||||
void toggleVarBottom(AstNodeDType* nodep, int depth, // per-iteration
|
||||
const ToggleEnt& above,
|
||||
AstVar* varp, AstVar* chgVarp) { // Constant
|
||||
AstCoverToggle* newp
|
||||
= new AstCoverToggle (varp->fileline(),
|
||||
newCoverInc(varp->fileline(), "", "v_toggle",
|
||||
varp->name()+above.m_comment),
|
||||
above.m_varRefp->cloneTree(true),
|
||||
above.m_chgRefp->cloneTree(true));
|
||||
m_modp->addStmtp(newp);
|
||||
}
|
||||
|
||||
void toggleVarRecurse(AstNodeDType* nodep, int depth, // per-iteration
|
||||
const ToggleEnt& above,
|
||||
AstVar* varp, AstVar* chgVarp) { // Constant
|
||||
if (AstBasicDType* bdtypep = nodep->castBasicDType()) {
|
||||
if (bdtypep->rangep()) {
|
||||
for (int index_docs=bdtypep->lsb(); index_docs<bdtypep->msb()+1; index_docs++) {
|
||||
int index_code = index_docs - bdtypep->lsb();
|
||||
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
|
||||
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code, 1),
|
||||
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code, 1));
|
||||
toggleVarBottom(nodep, depth+1,
|
||||
newent,
|
||||
varp, chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
} else {
|
||||
toggleVarBottom(nodep, chgVarp,
|
||||
dimension, selects_docs, selects_code,
|
||||
false, 0);
|
||||
toggleVarBottom(nodep, depth+1,
|
||||
above,
|
||||
varp, chgVarp);
|
||||
}
|
||||
}
|
||||
}
|
||||
void toggleVarBottom(AstVar* nodep, AstVar* chgVarp,
|
||||
int dimension, vector<int>& selects_docs, vector<int>& selects_code,
|
||||
bool bitsel, int bitindex_docs) {
|
||||
string comment = nodep->name();
|
||||
AstNode* varRefp = new AstVarRef(nodep->fileline(), nodep, false);
|
||||
AstNode* chgRefp = new AstVarRef(nodep->fileline(), chgVarp, true);
|
||||
// Now determine the name of, and how to get to the bit of this slice
|
||||
for (int dim=0; dim<dimension; dim++) {
|
||||
// Comments are strings, not symbols, so we don't need __BRA__ __KET__
|
||||
comment += "["+cvtToStr(selects_docs[dim])+"]";
|
||||
varRefp = new AstArraySel(nodep->fileline(), varRefp, selects_code[dim]);
|
||||
chgRefp = new AstArraySel(nodep->fileline(), chgRefp, selects_code[dim]);
|
||||
else if (AstArrayDType* adtypep = nodep->castArrayDType()) {
|
||||
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) {
|
||||
int index_code = index_docs - adtypep->lsb();
|
||||
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
|
||||
new AstArraySel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code),
|
||||
new AstArraySel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code));
|
||||
toggleVarRecurse(adtypep->dtypep(), depth+1,
|
||||
newent,
|
||||
varp, chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
}
|
||||
if (bitsel) {
|
||||
comment += "["+cvtToStr(bitindex_docs)+"]";
|
||||
int bitindex_code = bitindex_docs - nodep->lsb();
|
||||
varRefp = new AstSel(nodep->fileline(), varRefp, bitindex_code, 1);
|
||||
chgRefp = new AstSel(nodep->fileline(), chgRefp, bitindex_code, 1);
|
||||
else {
|
||||
nodep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<<nodep->prettyTypeName());
|
||||
}
|
||||
AstCoverToggle* newp = new AstCoverToggle (nodep->fileline(),
|
||||
newCoverInc(nodep->fileline(), "", "v_toggle", comment),
|
||||
varRefp, chgRefp);
|
||||
m_modp->addStmtp(newp);
|
||||
}
|
||||
|
||||
// VISITORS - LINE COVERAGE
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ private:
|
|||
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
|
||||
varp->widthSignedFrom(oldvarscp);
|
||||
} else {
|
||||
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, AstVar::LogicPacked(), width);
|
||||
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), width);
|
||||
}
|
||||
addmodp->addStmtp(varp);
|
||||
m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp));
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ private:
|
|||
// Width, not widthMin, as we may be in middle of BITSEL expression which
|
||||
// though it's one bit wide, needs the mask in the upper bits.
|
||||
// (Someday we'll have a valid bitmask instead of widths....)
|
||||
AstVar::LogicPacked(), nodep->width());
|
||||
AstLogicPacked(), nodep->width());
|
||||
if (!m_funcp) nodep->v3fatalSrc("Deep expression not under a function");
|
||||
m_funcp->addInitsp(varp);
|
||||
// Replace node tree with reference to var
|
||||
|
|
|
|||
|
|
@ -274,10 +274,13 @@ public:
|
|||
uint32_t array_lsb = 0;
|
||||
{
|
||||
AstVarRef* varrefp = nodep->memp()->castVarRef();
|
||||
if (!varrefp || !varrefp->varp()->arrayp(0)) { nodep->v3error("Readmem loading non-arrayed variable"); }
|
||||
else {
|
||||
if (!varrefp) { nodep->v3error("Readmem loading non-variable"); }
|
||||
else if (AstArrayDType* adtypep = varrefp->varp()->dtypep()->castArrayDType()) {
|
||||
puts(cvtToStr(varrefp->varp()->arrayElements()));
|
||||
array_lsb = varrefp->varp()->arrayp(0)->lsbConst();
|
||||
array_lsb = adtypep->lsb();
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Readmem loading non-arrayed variable");
|
||||
}
|
||||
}
|
||||
putbs(", ");
|
||||
|
|
@ -770,7 +773,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
|||
puts(nodep->name());
|
||||
puts(";\n");
|
||||
} else { // C++ signals
|
||||
ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes());
|
||||
ofp()->putAlign(nodep->isStatic(), nodep->dtypep()->widthAlignBytes(),
|
||||
nodep->dtypep()->widthTotalBytes());
|
||||
if (nodep->isInout()) puts("VL_INOUT");
|
||||
else if (nodep->isInput()) puts("VL_IN");
|
||||
else if (nodep->isOutput()) puts("VL_OUT");
|
||||
|
|
@ -793,7 +797,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
|||
} else {
|
||||
// Arrays need a small alignment, but may need different padding after.
|
||||
// For example three VL_SIG8's needs alignment 1 but size 3.
|
||||
ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes(), nodep->arrayElements()*nodep->widthAlignBytes());
|
||||
ofp()->putAlign(nodep->isStatic(), nodep->dtypep()->widthAlignBytes(),
|
||||
nodep->dtypep()->widthTotalBytes());
|
||||
if (nodep->isStatic() && prefixIfImp=="") puts("static ");
|
||||
if (nodep->isStatic()) puts("VL_ST_"); else puts("VL_");
|
||||
if (nodep->widthMin() <= 8) {
|
||||
|
|
@ -809,7 +814,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
|||
}
|
||||
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
|
||||
puts(nodep->name());
|
||||
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
// This isn't very robust and may need cleanup for other data types
|
||||
for (AstArrayDType* arrayp=nodep->dtypep()->castArrayDType(); arrayp; arrayp = arrayp->dtypep()->castArrayDType()) {
|
||||
puts("["+cvtToStr(arrayp->elementsConst())+"]");
|
||||
}
|
||||
puts(","+cvtToStr(nodep->msb())+","+cvtToStr(nodep->lsb()));
|
||||
|
|
@ -1154,18 +1160,22 @@ void EmitCImp::emitVarResets(AstModule* modp) {
|
|||
}
|
||||
else if (AstInitArray* initarp = varp->initp()->castInitArray()) {
|
||||
AstConst* constsp = initarp->initsp()->castConst();
|
||||
if (!varp->arraysp()) varp->v3fatalSrc("InitArray under non-arrayed var");
|
||||
for (int i=0; i<varp->arraysp()->elementsConst(); i++) {
|
||||
if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement");
|
||||
emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp);
|
||||
constsp = constsp->nextp()->castConst();
|
||||
if (AstArrayDType* arrayp = varp->dtypep()->castArrayDType()) {
|
||||
for (int i=0; i<arrayp->elementsConst(); i++) {
|
||||
if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement");
|
||||
emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp);
|
||||
constsp = constsp->nextp()->castConst();
|
||||
}
|
||||
} else {
|
||||
varp->v3fatalSrc("InitArray under non-arrayed var");
|
||||
}
|
||||
}
|
||||
else {
|
||||
int vects = 0;
|
||||
for (AstRange* arrayp=varp->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
// This isn't very robust and may need cleanup for other data types
|
||||
for (AstArrayDType* arrayp=varp->dtypep()->castArrayDType(); arrayp; arrayp = arrayp->dtypep()->castArrayDType()) {
|
||||
int vecnum = vects++;
|
||||
if (arrayp->msbConst() < arrayp->lsbConst()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
|
||||
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
|
||||
string ivar = string("__Vi")+cvtToStr(vecnum);
|
||||
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
|
||||
puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";");
|
||||
|
|
@ -1413,15 +1423,16 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
|
|||
}
|
||||
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
|
||||
if (doit) {
|
||||
int sigbytes = varp->widthAlignBytes();
|
||||
if (varp->isUsedClock() && varp->widthMin()==1) sigbytes = 0;
|
||||
else if (varp->arraysp()) sigbytes=7;
|
||||
else if (varp->isScBv()) sigbytes=6;
|
||||
else if (sigbytes==8) sigbytes=5;
|
||||
else if (sigbytes==4) sigbytes=4;
|
||||
else if (sigbytes==2) sigbytes=2;
|
||||
else if (sigbytes==1) sigbytes=1;
|
||||
if (size==sigbytes) {
|
||||
int sigbytes = varp->dtypep()->widthAlignBytes();
|
||||
int sortbytes = 7;
|
||||
if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0;
|
||||
else if (varp->dtypep()->castArrayDType()) sortbytes=7;
|
||||
else if (varp->isScBv()) sortbytes=6;
|
||||
else if (sigbytes==8) sortbytes=5;
|
||||
else if (sigbytes==4) sortbytes=4;
|
||||
else if (sigbytes==2) sortbytes=2;
|
||||
else if (sigbytes==1) sortbytes=1;
|
||||
if (size==sortbytes) {
|
||||
emitVarDecl(varp, prefixIfImp);
|
||||
}
|
||||
}
|
||||
|
|
@ -1889,7 +1900,8 @@ class EmitCTrace : EmitCStmts {
|
|||
puts("(");
|
||||
if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP(");
|
||||
varrefp->iterate(*this); // Put var name out
|
||||
if (varp->arraysp()) {
|
||||
// Tracing only supports 1D arrays
|
||||
if (varp->dtypep()->castArrayDType()) {
|
||||
if (arrayindex==-2) puts("[i]");
|
||||
else if (arrayindex==-1) puts("[0]");
|
||||
else puts("["+cvtToStr(arrayindex)+"]");
|
||||
|
|
|
|||
|
|
@ -423,11 +423,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
if (nodep->isSigned()) puts("signed ");
|
||||
nodep->dtypep()->iterateChildren(*this);
|
||||
puts(nodep->name());
|
||||
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
puts(" ["+cvtToStr(arrayp->msbConst())
|
||||
+":"+cvtToStr(arrayp->lsbConst())
|
||||
+"]");
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstNodeText*, AstNUser*) {}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ private:
|
|||
if (!forrefp->varp()) {
|
||||
if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
|
||||
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
|
||||
forrefp->name(), AstVar::LogicPacked(), 1);
|
||||
forrefp->name(), AstLogicPacked(), 1);
|
||||
|
||||
newp->trace(m_modp->modTrace());
|
||||
m_modp->addStmtp(newp);
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ private:
|
|||
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->arraysp() && nodep->isIO()) {
|
||||
nodep->v3error("Arrayed variables may not be inputs nor outputs");
|
||||
if (nodep->isIO() && !nodep->dtypep()->castBasicDType()) {
|
||||
nodep->v3error("Unsupported: Inputs and outputs must be simple data types; no arrays");
|
||||
}
|
||||
if (m_ftaskp) nodep->funcLocal(true);
|
||||
if (nodep->isSigModPublic()) {
|
||||
|
|
@ -124,7 +124,7 @@ private:
|
|||
// Make a new temp wire
|
||||
string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
|
||||
AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname,
|
||||
AstVar::LogicPacked(), 1);
|
||||
AstLogicPacked(), 1);
|
||||
// We can't just add under the module, because we may be inside a generate, begin, etc.
|
||||
// We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards
|
||||
AstNode* addwherep = nodep; // Add to this element's next
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ private:
|
|||
AstVar* getBlockTemp(AstNode* nodep) {
|
||||
string newvarname = ((string)"__Vtemp"+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname,
|
||||
AstVar::LogicPacked(), nodep->widthMin());
|
||||
AstLogicPacked(), nodep->widthMin());
|
||||
m_funcp->addInitsp(varp);
|
||||
return varp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ private:
|
|||
// We can't have non-delayed assignments with same value on LHS and RHS
|
||||
// as we don't figure out variable ordering.
|
||||
// Delayed is OK though, as we'll decode the next state separately.
|
||||
if (nodep->varp()->arraysp()) clearOptimizable(nodep,"Array references");
|
||||
if (!nodep->varp()->dtypep()->castBasicDType()) clearOptimizable(nodep,"Array references/not basic");
|
||||
if (nodep->lvalue()) {
|
||||
if (m_inDlyAssign) {
|
||||
if (!(vscp->user1() & VU_LVDLY)) {
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
if (m_counting) {
|
||||
if (nodep->isUsedClock()) ++m_statVarClock;
|
||||
if (nodep->arraysp()) ++m_statVarArray;
|
||||
if (!nodep->arraysp()) m_statVarBytes += nodep->widthTotalBytes();
|
||||
if (nodep->dtypep()->castArrayDType()) ++m_statVarArray;
|
||||
else m_statVarBytes += nodep->dtypep()->widthTotalBytes();
|
||||
if (int(m_statVarWidths.size()) <= nodep->width()) {
|
||||
m_statVarWidths.resize(nodep->width()+5);
|
||||
}
|
||||
|
|
@ -106,7 +106,9 @@ private:
|
|||
allNodes(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_counting) {
|
||||
if (!nodep->varp()->arraysp()) m_statVarScpBytes += nodep->varp()->widthTotalBytes();
|
||||
if (nodep->varp()->dtypep()->castBasicDType()) {
|
||||
m_statVarScpBytes += nodep->varp()->dtypep()->widthTotalBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ public:
|
|||
UINFO(9," SimVARREF "<<nodep<<endl);
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
if (nodep->lvalue()) {
|
||||
m_outWidth += nodep->varp()->widthTotalBytes();
|
||||
m_outWidth += nodep->varp()->dtypep()->widthTotalBytes();
|
||||
m_outVarps.push_back(vscp);
|
||||
} else {
|
||||
// We'll make the table with a separate natural alignment for each
|
||||
|
|
@ -182,16 +182,19 @@ private:
|
|||
// Index into our table
|
||||
AstVar* indexVarp = new AstVar (nodep->fileline(), AstVarType::BLOCKTEMP,
|
||||
"__Vtableidx" + cvtToStr(m_modTables),
|
||||
AstVar::LogicPacked(), m_inWidth);
|
||||
AstLogicPacked(), m_inWidth);
|
||||
m_modp->addStmtp(indexVarp);
|
||||
AstVarScope* indexVscp = new AstVarScope (indexVarp->fileline(), m_scopep, indexVarp);
|
||||
m_scopep->addVarp(indexVscp);
|
||||
|
||||
// Change it variable
|
||||
AstVar* chgVarp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__Vtablechg" + cvtToStr(m_modTables),
|
||||
AstVar::LogicPacked(), m_outVarps.size());
|
||||
chgVarp->addArraysp(new AstRange (nodep->fileline(), VL_MASK_I(m_inWidth), 0));
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstVar* chgVarp
|
||||
= new AstVar (fl, AstVarType::MODULETEMP,
|
||||
"__Vtablechg" + cvtToStr(m_modTables),
|
||||
new AstArrayDType (fl,
|
||||
new AstBasicDType(fl, AstLogicPacked(), m_outVarps.size()),
|
||||
new AstRange (fl, VL_MASK_I(m_inWidth), 0)));
|
||||
chgVarp->isConst(true);
|
||||
chgVarp->initp(new AstInitArray (nodep->fileline(), NULL));
|
||||
m_modp->addStmtp(chgVarp);
|
||||
|
|
@ -229,11 +232,13 @@ private:
|
|||
for (deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
|
||||
AstVarScope* outvscp = *it;
|
||||
AstVar* outvarp = outvscp->varp();
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstVar* tablevarp
|
||||
= new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
|
||||
= new AstVar (fl, AstVarType::MODULETEMP,
|
||||
"__Vtable" + cvtToStr(m_modTables) +"_"+outvarp->name(),
|
||||
AstVar::LogicPacked(), outvarp->widthMin());
|
||||
tablevarp->addArraysp(new AstRange (nodep->fileline(), VL_MASK_I(m_inWidth), 0));
|
||||
new AstArrayDType (fl,
|
||||
new AstBasicDType(fl, AstLogicPacked(), outvarp->widthMin()),
|
||||
new AstRange (fl, VL_MASK_I(m_inWidth), 0)));
|
||||
tablevarp->isConst(true);
|
||||
tablevarp->isStatic(true);
|
||||
tablevarp->initp(new AstInitArray (nodep->fileline(), NULL));
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ private:
|
|||
if (!activityNumber) activityNumber++; // For simplicity, always create it
|
||||
int activityBits = VL_WORDS_I(activityNumber)*VL_WORDSIZE; // For tighter code; round to next 32 bit point.
|
||||
AstVar* newvarp = new AstVar (m_chgFuncp->fileline(), AstVarType::MODULETEMP,
|
||||
"__Vm_traceActivity", AstVar::LogicPacked(), activityBits);
|
||||
"__Vm_traceActivity", AstLogicPacked(), activityBits);
|
||||
m_topModp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(newvarp->fileline(), m_highScopep, newvarp);
|
||||
m_highScopep->addVarp(newvscp);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,11 @@ private:
|
|||
return "Inlined leading underscore";
|
||||
if (nodep->width() > 256) return "Wide bus > 256 bits";
|
||||
if (nodep->arrayElements() > 32) return "Wide memory > 32 ents";
|
||||
if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
|
||||
if (!(nodep->dtypep()->castBasicDType()
|
||||
|| (nodep->dtypep()->castArrayDType()
|
||||
&& nodep->dtypep()->castArrayDType()->dtypep()->castBasicDType()))) {
|
||||
return "Unsupported: Multi-dimensional array";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ private:
|
|||
AstVar* enp = new AstVar (outrefp->varp()->fileline(),
|
||||
AstVarType::MODULETEMP,
|
||||
outrefp->name() + "__en" + suffix + cvtToStr(m_unique++),
|
||||
AstVar::LogicPacked(), width);
|
||||
AstLogicPacked(), width);
|
||||
enp->varType2Out();
|
||||
|
||||
if (enp->width() != enrhsp->width()) {
|
||||
|
|
@ -381,7 +381,7 @@ private:
|
|||
AstVar* newlhsp = new AstVar(lhsp->fileline(),
|
||||
AstVarType::MODULETEMP,
|
||||
lhsp->name()+"__lhs"+cvtToStr(m_unique++),
|
||||
AstVar::LogicPacked(), w);
|
||||
AstLogicPacked(), w);
|
||||
nodep->addStmtp(newlhsp);
|
||||
|
||||
// now append this driver to the driver logic.
|
||||
|
|
@ -396,7 +396,7 @@ private:
|
|||
bitselp = new AstVar(lhsp->fileline(),
|
||||
AstVarType::MODULETEMP,
|
||||
lhsp->name()+"__sel"+cvtToStr(m_unique-1),
|
||||
AstVar::LogicPacked(), ws);
|
||||
AstLogicPacked(), ws);
|
||||
//
|
||||
nodep->addStmtp(bitselp);
|
||||
nodep->addStmtp(new AstAssignW(lhsp->fileline(),
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ private:
|
|||
else {
|
||||
string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
|
||||
AstVar::LogicPacked(), prep->width());
|
||||
AstLogicPacked(), prep->width());
|
||||
m_modp->addStmtp(varp);
|
||||
|
||||
AstNode* abovep = prep->backp(); // Grab above point before loose it w/ next replace
|
||||
|
|
@ -288,7 +288,7 @@ private:
|
|||
+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* newvarp
|
||||
= new AstVar (nodep->fileline(), AstVarType::XTEMP, newvarname,
|
||||
AstVar::LogicPacked(), nodep->width());
|
||||
AstLogicPacked(), nodep->width());
|
||||
m_statUnkVars++;
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
|
|
@ -327,7 +327,7 @@ private:
|
|||
// Guard against reading/writing past end of bit vector array
|
||||
int maxmsb = 0;
|
||||
bool lvalue = false;
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
|
||||
lvalue = varrefp->lvalue();
|
||||
maxmsb = (varrefp->varp()->width()-1);
|
||||
|
|
@ -382,8 +382,10 @@ private:
|
|||
int maxmsb = 0;
|
||||
bool lvalue = false;
|
||||
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
|
||||
AstArrayDType* adtypep = varrefp->varp()->dtypeDimensionp(dimension)->castArrayDType();
|
||||
if (!adtypep) nodep->v3fatalSrc("ArraySel to type without array at same depth");
|
||||
lvalue = varrefp->lvalue();
|
||||
maxmsb = (varrefp->varp()->arrayp(dimension)->elementsConst()-1);
|
||||
maxmsb = adtypep->elementsConst()-1;
|
||||
} else if (AstConst* lhconstp = basefromp->castConst()) {
|
||||
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
|
||||
maxmsb = lhconstp->widthMin();
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ private:
|
|||
|
||||
virtual void visit(AstSel* nodep, AstNUser* vup) {
|
||||
if (vup->c()->prelim()) {
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-selWidth: ");
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
|
|
@ -299,7 +300,7 @@ private:
|
|||
int frommsb = nodep->fromp()->width() - 1;
|
||||
int fromlsb = 0;
|
||||
AstNodeVarRef* varrp = nodep->fromp()->castNodeVarRef();
|
||||
if (varrp && varrp->varp()->dtypep()->rangep()) { // Selecting a bit from a multibit register
|
||||
if (varrp && varrp->varp()->basicp()->rangep()) { // Selecting a bit from a multibit register
|
||||
frommsb = varrp->varp()->msbMaxSelect(); // Corrected for negative lsb
|
||||
fromlsb = varrp->varp()->lsb();
|
||||
}
|
||||
|
|
@ -314,6 +315,9 @@ private:
|
|||
<<(nodep->lsbp()->width()!=nodep->lsbp()->widthMin()
|
||||
?" or "+cvtToStr(nodep->lsbp()->widthMin()):"")
|
||||
<<" bits.");
|
||||
UINFO(1," Related node: "<<nodep<<endl);
|
||||
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
|
||||
if (varrp) UINFO(1," Related dtype: "<<varrp->varp()->dtypep()<<endl);
|
||||
}
|
||||
if (nodep->lsbp()->castConst() && nodep->msbConst() > frommsb) {
|
||||
// See also warning in V3Const
|
||||
|
|
@ -322,6 +326,9 @@ private:
|
|||
nodep->v3error("Selection index out of range: "
|
||||
<<nodep->msbConst()<<":"<<nodep->lsbConst()
|
||||
<<" outside "<<frommsb<<":"<<fromlsb);
|
||||
UINFO(1," Related node: "<<nodep<<endl);
|
||||
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
|
||||
if (varrp) UINFO(1," Related dtype: "<<varrp->varp()->dtypep()<<endl);
|
||||
}
|
||||
// iterate FINAL is two blocks above
|
||||
widthCheck(nodep,"Extract Range",nodep->lsbp(),selwidth,selwidth,true);
|
||||
|
|
@ -339,28 +346,34 @@ private:
|
|||
//
|
||||
int frommsb;
|
||||
int fromlsb;
|
||||
if (!varrp->varp()->arrayp(dimension)) {
|
||||
nodep->v3fatalSrc("Array reference exceeds dimension of array");
|
||||
}
|
||||
if (1) { // ARRAY slice extraction
|
||||
AstNodeDType* ddtypep = varrp->varp()->dtypeDimensionp(dimension);
|
||||
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
||||
int outwidth = varrp->width(); // Width of variable
|
||||
frommsb = varrp->varp()->arrayp(dimension)->msbConst();
|
||||
fromlsb = varrp->varp()->arrayp(dimension)->lsbConst();
|
||||
frommsb = adtypep->msb();
|
||||
fromlsb = adtypep->lsb();
|
||||
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
|
||||
}
|
||||
else {
|
||||
nodep->v3fatalSrc("Array reference exceeds dimension of array");
|
||||
frommsb = fromlsb = 0;
|
||||
}
|
||||
int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,FINAL).p());
|
||||
if (widthBad(nodep->bitp(),selwidth,selwidth)
|
||||
&& nodep->bitp()->width()!=32)
|
||||
&& nodep->bitp()->width()!=32) {
|
||||
nodep->v3warn(WIDTH,"Bit extraction of array["<<frommsb<<":"<<fromlsb<<"] requires "
|
||||
<<selwidth<<" bit index, not "
|
||||
<<nodep->bitp()->width()
|
||||
<<(nodep->bitp()->width()!=nodep->bitp()->widthMin()
|
||||
?" or "+cvtToStr(nodep->bitp()->widthMin()):"")
|
||||
<<" bits.");
|
||||
UINFO(1," Related node: "<<nodep<<endl);
|
||||
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
|
||||
if (varrp) UINFO(1," Related depth: "<<dimension<<" dtype: "<<ddtypep<<endl);
|
||||
}
|
||||
widthCheck(nodep,"Extract Range",nodep->bitp(),selwidth,selwidth,true);
|
||||
}
|
||||
}
|
||||
|
|
@ -473,6 +486,13 @@ private:
|
|||
virtual void visit(AstScopeName* nodep, AstNUser* vup) {
|
||||
// Only used in Displays which don't care....
|
||||
}
|
||||
virtual void visit(AstArrayDType* nodep, AstNUser* vup) {
|
||||
// Lower datatype determines the width
|
||||
nodep->dtypep()->iterateAndNext(*this,vup);
|
||||
// But also cleanup array size
|
||||
nodep->arrayp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->widthFrom(nodep->dtypep());
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep, AstNUser* vup) {
|
||||
if (nodep->rangep()) {
|
||||
nodep->rangep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
|
|
@ -487,8 +507,6 @@ private:
|
|||
// We can't skip this step when width()!=0, as creating a AstVar
|
||||
// with non-constant range gets size 1, not size 0.
|
||||
int width=1; int mwidth=1;
|
||||
nodep->arraysp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
|
||||
// Parameters if implicit untyped inherit from what they are assigned to
|
||||
AstBasicDType* bdtypep = nodep->dtypep()->castBasicDType();
|
||||
if (nodep->isParam() && bdtypep && bdtypep->implicit()) {
|
||||
|
|
@ -535,11 +553,9 @@ private:
|
|||
}
|
||||
//if (debug()>=9) { nodep->dumpTree(cout," VRin "); nodep->varp()->dumpTree(cout," forvar "); }
|
||||
// Note genvar's are also entered as integers
|
||||
AstBasicDType* bdtypep = nodep->varp()->dtypep()->castBasicDType();
|
||||
if (bdtypep && bdtypep->isSloppy()
|
||||
&& nodep->backp()->castNodeAssign()) { // On LHS
|
||||
// Consider Integers on LHS to sized (else would be unsized.)
|
||||
nodep->width(bdtypep->width(),bdtypep->width());
|
||||
if (nodep->backp()->castNodeAssign() && nodep->lvalue()) { // On LHS
|
||||
// Consider Integers on LHS to sized (else may be unsized.)
|
||||
nodep->width(nodep->varp()->width(), nodep->varp()->width());
|
||||
} else {
|
||||
nodep->widthFrom(nodep->varp());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,22 +74,29 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void selCheckDimension(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
|
||||
AstNodeDType* dtypeForExtractp(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
|
||||
// Perform error checks on the node
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: ");
|
||||
int dimensions = varp->arrayDimensions();
|
||||
if (dimension < dimensions) {
|
||||
AstNodeDType* ddtypep = varp->dtypeDimensionp(dimension);
|
||||
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
||||
if (rangedSelect) {
|
||||
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
|
||||
return NULL;
|
||||
}
|
||||
} else if (dimension > dimensions) { // Too many indexes provided
|
||||
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
|
||||
} else if (dimension == dimensions) { // Right number, but...
|
||||
if (!varp->dtypep()->rangep()) {
|
||||
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
|
||||
}
|
||||
return adtypep;
|
||||
}
|
||||
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (!adtypep->rangep()) {
|
||||
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
|
||||
return NULL;
|
||||
}
|
||||
return adtypep;
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
|
||||
|
|
@ -133,14 +140,14 @@ private:
|
|||
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
|
||||
if (!varp->dtypep()->rangep()) {
|
||||
if (!varp->basicp()->rangep()) {
|
||||
// vector without range is ok, for example a INTEGER x; y = x[21:0];
|
||||
return underp;
|
||||
} else {
|
||||
if (!varp->dtypep()->rangep()->msbp()->castConst()
|
||||
|| !varp->dtypep()->rangep()->lsbp()->castConst())
|
||||
if (!varp->basicp()->rangep()->msbp()->castConst()
|
||||
|| !varp->basicp()->rangep()->lsbp()->castConst())
|
||||
varp->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(varp)
|
||||
if (varp->dtypep()->rangep()->littleEndian()) {
|
||||
if (varp->basicp()->rangep()->littleEndian()) {
|
||||
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
|
||||
AstNode* newp = newSubNeg(varp->msb(), underp);
|
||||
return newp;
|
||||
|
|
@ -169,8 +176,7 @@ private:
|
|||
// So, see if we're sitting under a variable's arrayp.
|
||||
AstNode* huntbackp = nodep;
|
||||
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
|
||||
if (huntbackp->backp()->castVar()
|
||||
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
|
||||
if (huntbackp->backp()->castArrayDType()) {
|
||||
} else {
|
||||
// Little endian bits are legal, just remember to swap
|
||||
// Warning is in V3Width to avoid false warnings when in "off" generate if's
|
||||
|
|
@ -189,26 +195,23 @@ private:
|
|||
// lhsp/rhsp do not need to be constant
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
|
||||
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
|
||||
selCheckDimension(nodep, basefromp, dimension, false);
|
||||
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, false);
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
|
||||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-vsbmd: ");
|
||||
if (varp->arrayp(dimension)) {
|
||||
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
||||
// SELBIT(array, index) -> ARRAYSEL(array, index)
|
||||
AstRange* arrayp = varp->arrayp(dimension); // NULL checked above
|
||||
AstNode* subp = bitp;
|
||||
if (!arrayp->lsbp()->isZero() || arrayp->msbConst()<0) {
|
||||
subp = newSubNeg (subp, arrayp->lsbConst());
|
||||
if (adtypep->lsb()!=0 || adtypep->msb()<0) {
|
||||
subp = newSubNeg (subp, adtypep->lsb());
|
||||
}
|
||||
AstArraySel* newp = new AstArraySel
|
||||
(nodep->fileline(),
|
||||
fromp,
|
||||
subp);
|
||||
AstArraySel* newp = new AstArraySel (nodep->fileline(),
|
||||
fromp, subp);
|
||||
UINFO(6," newd"<<dimension<<" "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else {
|
||||
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (adtypep) {} // unused
|
||||
// SELBIT(range, index) -> SEL(array, index, 1)
|
||||
AstSel* newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
|
|
@ -218,6 +221,11 @@ private:
|
|||
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension");
|
||||
// How to recover? We'll strip a dimension.
|
||||
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSelExtract* nodep, AstNUser*) {
|
||||
|
|
@ -238,25 +246,33 @@ private:
|
|||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
vlsint32_t msb = msbp->castConst()->toSInt();
|
||||
vlsint32_t lsb = lsbp->castConst()->toSInt();
|
||||
selCheckDimension(nodep, basefromp, dimension, msb!=lsb);
|
||||
if (varp->dtypep()->rangep() && varp->dtypep()->rangep()->littleEndian()) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, msb!=lsb);
|
||||
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (adtypep) {} // Unused
|
||||
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
}
|
||||
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
|
||||
msb +1-lsb);
|
||||
AstSel* newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(lsbp, basefromp),
|
||||
widthp);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(msbp); msbp=NULL;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal range select; variable already selected, or bad dimension");
|
||||
// How to recover? We'll strip a dimension.
|
||||
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
|
||||
msb +1-lsb);
|
||||
AstSel* newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(lsbp, basefromp),
|
||||
widthp);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(msbp); msbp=NULL;
|
||||
}
|
||||
|
||||
void replaceSelPlusMinus(AstNodePreSel* nodep) {
|
||||
|
|
@ -274,41 +290,49 @@ private:
|
|||
AstVar* varp = varFromBasefrom(basefromp);
|
||||
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
|
||||
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
|
||||
selCheckDimension(nodep, basefromp, dimension, width!=1);
|
||||
AstSel* newp = NULL;
|
||||
if (nodep->castSelPlus()) {
|
||||
if (varp->dtypep()->rangep() && varp->dtypep()->rangep()->littleEndian()) {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg((varp->msb()-width+1), rhsp),
|
||||
widthp);
|
||||
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, width!=1);
|
||||
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (adtypep) {} // Unused
|
||||
AstSel* newp = NULL;
|
||||
if (nodep->castSelPlus()) {
|
||||
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg((varp->msb()-width+1), rhsp),
|
||||
widthp);
|
||||
} else {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(rhsp, basefromp),
|
||||
widthp);
|
||||
}
|
||||
} else if (nodep->castSelMinus()) {
|
||||
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg(varp->msb(), rhsp),
|
||||
widthp);
|
||||
} else {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg(rhsp, varp->lsb()+(width-1)),
|
||||
widthp);
|
||||
}
|
||||
} else {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(rhsp, basefromp),
|
||||
widthp);
|
||||
nodep->v3fatalSrc("Bad Case");
|
||||
}
|
||||
} else if (nodep->castSelMinus()) {
|
||||
if (varp->dtypep()->rangep() && varp->dtypep()->rangep()->littleEndian()) {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg(varp->msb(), rhsp),
|
||||
widthp);
|
||||
} else {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
|
||||
newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubNeg(rhsp, varp->lsb()+(width-1)),
|
||||
widthp);
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad Case");
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal +: or -: select; variable already selected, or bad dimension");
|
||||
// How to recover? We'll strip a dimension.
|
||||
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstSelPlus* nodep, AstNUser*) {
|
||||
replaceSelPlusMinus(nodep);
|
||||
|
|
|
|||
|
|
@ -2613,9 +2613,21 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
|
|||
if (type == AstVarType::GENVAR) {
|
||||
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
|
||||
}
|
||||
|
||||
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
||||
AstNodeDType* arrayDTypep = dtypep;
|
||||
if (arrayp) {
|
||||
while (arrayp->nextp()) arrayp = arrayp->nextp()->castRange();
|
||||
while (arrayp) {
|
||||
AstRange* prevp = arrayp->backp()->castRange();
|
||||
if (prevp) arrayp->unlinkFrBack();
|
||||
arrayDTypep = new AstArrayDType(arrayp->fileline(), arrayDTypep, arrayp);
|
||||
arrayp = prevp;
|
||||
}
|
||||
}
|
||||
|
||||
AstVar* nodep = new AstVar(fileline, type, name,
|
||||
dtypep,
|
||||
arrayp);
|
||||
arrayDTypep);
|
||||
nodep->addAttrsp(attrsp);
|
||||
if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
|
||||
if (GRAMMARP->m_varIO != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varIO);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ compile (
|
|||
fails=>$Self->{v3},
|
||||
nc=>0,
|
||||
expect=>
|
||||
'%Error: t/t_mem_multi_io_bad.v:\d+: Arrayed variables may not be inputs nor outputs
|
||||
'%Error: t/t_mem_multi_io_bad.v:\d+: Unsupported: Inputs and outputs must be simple data types; no arrays
|
||||
%Error: Exiting due to.*',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ compile (
|
|||
fails=>$Self->{v3},
|
||||
nc=>0, # Need to get it not to give the prompt
|
||||
expect=>
|
||||
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dimn
|
||||
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dimn
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim1
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim0nv
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dim0nv
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0nv
|
||||
.*%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ module t (/*AUTOARG*/
|
|||
end
|
||||
|
||||
reg [71:0] wread;
|
||||
reg wreadb;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
//$write("cyc==%0d crc=%x i[%d][%d][%d] nar=%x wide=%x\n",cyc, crc, index0,index1,index2, narrow, wide);
|
||||
|
|
@ -58,12 +59,14 @@ module t (/*AUTOARG*/
|
|||
index1 <= crc[3:2];
|
||||
index2 <= crc[6:4];
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
|
||||
// We never read past bounds, or get unspecific results
|
||||
// We also never read lowest indexes, as writing outside of range may corrupt them
|
||||
if (index0>=0+1 && index0<=2 && index1>=1+1 && index1<=3 && index2>=2+1 && index2<=5) begin
|
||||
narrow <= ({narrow[6:0], narrow[7]^narrow[0]}
|
||||
^ {memn[index0][index1][index2]});
|
||||
wread = memw[index0][index1][index2];
|
||||
wreadb = memw[index0][index1][index2][2];
|
||||
wide <= ({wide[70:0], wide[71]^wide[2]^wide[0]} ^ wread);
|
||||
//$write("Get memw[%d][%d][%d] -> %x\n",index0,index1,index2, wread);
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,17 @@ module t (
|
|||
little little (.clk(CLK));
|
||||
glbl glbl ();
|
||||
|
||||
// A vector
|
||||
logic [2:1] vec [4:3];
|
||||
|
||||
integer val = 0;
|
||||
always @ (posedge CLK) begin
|
||||
if (RESET) val <= 0;
|
||||
else val <= val + 1;
|
||||
vec[3] <= val[1:0];
|
||||
vec[4] <= val[3:2];
|
||||
end
|
||||
|
||||
initial RESET = 1'b1;
|
||||
always @ (posedge CLK)
|
||||
RESET <= glbl.GSR;
|
||||
|
|
|
|||
|
|
@ -1,89 +0,0 @@
|
|||
$version Generated by SpTraceVcd $end
|
||||
$date Sat Sep 26 15:04:50 2009
|
||||
$end
|
||||
$timescale 1ns $end
|
||||
|
||||
$scope module TOP $end
|
||||
$var wire 1 3 CLK $end
|
||||
$var wire 1 4 RESET $end
|
||||
$scope module v $end
|
||||
$var wire 1 3 CLK $end
|
||||
$var wire 1 # RESET $end
|
||||
$scope module glbl $end
|
||||
$var wire 1 2 GSR $end
|
||||
$upscope $end
|
||||
$scope module little $end
|
||||
$var wire 1 3 clk $end
|
||||
$var wire 128 . i128 [63:190] $end
|
||||
$var wire 49 , i48 [1:49] $end
|
||||
$var wire 8 + i8 [0:7] $end
|
||||
$upscope $end
|
||||
$scope module neg $end
|
||||
$var wire 1 3 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
|
||||
$enddefinitions $end
|
||||
|
||||
|
||||
#0
|
||||
1#
|
||||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
12
|
||||
14
|
||||
03
|
||||
#1
|
||||
#2
|
||||
#3
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
13
|
||||
#4
|
||||
#5
|
||||
#6
|
||||
03
|
||||
#7
|
||||
02
|
||||
#8
|
||||
#9
|
||||
0#
|
||||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
04
|
||||
13
|
||||
#10
|
||||
#11
|
||||
#12
|
||||
03
|
||||
#13
|
||||
#14
|
||||
#15
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
13
|
||||
#16
|
||||
#17
|
||||
#18
|
||||
03
|
||||
#19
|
||||
#20
|
||||
|
|
@ -21,7 +21,7 @@ if ($Self->{v3}) {
|
|||
);
|
||||
|
||||
vcd_identical ("$Self->{obj_dir}/simx.vcd",
|
||||
"t/$Self->{name}.out");
|
||||
"t/t_trace_public.out");
|
||||
}
|
||||
|
||||
ok(1);
|
||||
|
|
|
|||
|
|
@ -1,89 +0,0 @@
|
|||
$version Generated by SpTraceVcd $end
|
||||
$date Sat Sep 26 15:05:35 2009
|
||||
$end
|
||||
$timescale 1ns $end
|
||||
|
||||
$scope module TOP $end
|
||||
$var wire 1 2 CLK $end
|
||||
$var wire 1 3 RESET $end
|
||||
$scope module v $end
|
||||
$var wire 1 2 CLK $end
|
||||
$var wire 1 # RESET $end
|
||||
$scope module glbl $end
|
||||
$var wire 1 4 GSR $end
|
||||
$upscope $end
|
||||
$scope module little $end
|
||||
$var wire 1 2 clk $end
|
||||
$var wire 128 . i128 [63:190] $end
|
||||
$var wire 49 , i48 [1:49] $end
|
||||
$var wire 8 + i8 [0:7] $end
|
||||
$upscope $end
|
||||
$scope module neg $end
|
||||
$var wire 1 2 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
|
||||
$enddefinitions $end
|
||||
|
||||
|
||||
#0
|
||||
1#
|
||||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
13
|
||||
02
|
||||
14
|
||||
#1
|
||||
#2
|
||||
#3
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
12
|
||||
#4
|
||||
#5
|
||||
#6
|
||||
02
|
||||
#7
|
||||
04
|
||||
#8
|
||||
#9
|
||||
0#
|
||||
b00000000 $
|
||||
b000000000000000000000000000000000000000000000000 %
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
|
||||
b00000000 +
|
||||
b0000000000000000000000000000000000000000000000000 ,
|
||||
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
|
||||
03
|
||||
12
|
||||
#10
|
||||
#11
|
||||
#12
|
||||
02
|
||||
#13
|
||||
#14
|
||||
#15
|
||||
b11111111 $
|
||||
b111111111111111111111111111111111111111111111111 %
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
|
||||
b11111111 +
|
||||
b1111111111111111111111111111111111111111111111111 ,
|
||||
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
|
||||
12
|
||||
#16
|
||||
#17
|
||||
#18
|
||||
02
|
||||
#19
|
||||
#20
|
||||
|
|
@ -21,7 +21,7 @@ if ($Self->{v3}) {
|
|||
);
|
||||
|
||||
vcd_identical ("$Self->{obj_dir}/simx.vcd",
|
||||
"t/$Self->{name}.out");
|
||||
"t/t_trace_public.out");
|
||||
# vcd_identical doesn't detect "$var a.b;" vs "$scope module a; $var b;"
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/module glbl/i);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue