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