Internals: Move array definitions to AstArrayDType instead of under AstVars.

Prep work for more complicated data types.
This commit is contained in:
Wilson Snyder 2009-11-04 22:31:53 -05:00
parent db2c6820ee
commit 700c1f836d
35 changed files with 435 additions and 454 deletions

View File

@ -62,6 +62,7 @@ sub diff_dir {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{b} = $fn;
}
my $any;
foreach my $base (sort (keys %files)) {
my $a = $files{$base}{a};
my $b = $files{$base}{b};
@ -70,6 +71,7 @@ sub diff_dir {
print "= $a <-> $b\n";
diff_file($a,$b);
}
$any or warn "%Warning: No .tree files found\n";
}
sub diff_file {

View File

@ -32,6 +32,9 @@
// Things like:
// class V3AstNode;
// Hint class so we can choose constructors
class AstLogicPacked {};
//######################################################################
class AstType {
@ -1184,7 +1187,9 @@ struct AstNodeDType : public AstNode {
AstNodeDType(FileLine* fl) : AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeDType)
// Accessors
AstRange* rangep();
virtual AstBasicDType* basicp() = 0; // (Slow) recurse down to find basic data type
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
};
struct AstNodeSel : public AstNodeBiop {

View File

@ -35,11 +35,6 @@
//======================================================================
// Special methods
AstRange* AstNodeDType::rangep() {
if (castBasicDType()) return castBasicDType()->rangep();
else return NULL;
}
// We need these here, because the classes they point to aren't defined when we declare the class
bool AstNodeVarRef::broken() const { return ((m_varScopep && !m_varScopep->brokeExists())
|| (m_varp && !m_varp->brokeExists())); }
@ -52,6 +47,20 @@ int AstNodeSel::bitConst() const {
AstConst* constp=bitp()->castConst(); return (constp?constp->toSInt():0);
}
int AstBasicDType::widthAlignBytes() const {
if (width()<=8) return 1;
else if (width()<=16) return 2;
else if (isQuad()) return 8;
else return 4;
}
int AstBasicDType::widthTotalBytes() const {
if (width()<=8) return 1;
else if (width()<=16) return 2;
else if (isQuad()) return 8;
else return widthWords()*(VL_WORDSIZE/8);
}
bool AstVar::isSigPublic() const {
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
}
@ -77,20 +86,6 @@ void AstVar::combineType(AstVarType type) {
m_tristate = true;
}
int AstVar::widthAlignBytes() const {
if (width()<=8) return 1;
else if (width()<=16) return 2;
else if (isSc() ? isScQuad() : isQuad()) return 8;
else return 4;
}
int AstVar::widthTotalBytes() const {
if (width()<=8) return 1;
else if (width()<=16) return 2;
else if (isSc() ? isScQuad() : isQuad()) return 8;
else return widthWords()*(VL_WORDSIZE/8);
}
string AstVar::verilogKwd() const {
if (isInout()) {
return "inout";
@ -137,32 +132,61 @@ string AstVar::scType() const {
}
}
AstRange* AstVar::arrayp(int dimension) const {
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
if ((dimension--)==0) return arrayp;
AstNodeDType* AstVar::dtypeDimensionp(int dimension) const {
// dimension passed from AstArraySel::dimension
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
// which is the lowest in the dtype list.
// ref order: a[1][2][3][4]
// Created as: reg [4] a [1][2][3];
// *or* reg a [1][2][3][4];
// // The bit select is optional; used only if "leftover" []'s
// SEL: SEL4(SEL3(SEL2(SEL1(VARREF0 a))))
// DECL: VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (DT RANGE3))))
// *or* VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (ARRAYSEL3 (DT))))
// SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0
int dim = 0;
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
if ((dim++)==dimension) {
return dtypep;
}
dtypep = adtypep->dtypep();
continue;
} else if (AstBasicDType* adtypep = dtypep->castBasicDType()) {
// AstBasicDType - nothing below, return null
if (adtypep->rangep()) {
if ((dim++) == dimension) {
return adtypep;
}
}
return NULL;
}
// Node no ->next in loop; use continue where necessary
break;
}
return NULL;
}
int AstVar::arrayDimensions() const {
int entries=0;
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
entries++;
}
return entries;
}
uint32_t AstVar::arrayElements() const {
uint32_t entries=1;
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
entries *= arrayp->elementsConst();
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
entries *= adtypep->elementsConst();
dtypep = adtypep->dtypep();
} else {
// AstBasicDType - nothing below, 1
break;
}
}
return entries;
}
// Special operators
int AstArraySel::dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
// Only called after V3Param; so only ArraySel's need to be recursed
int AstArraySel::dimension(AstNode* nodep) {
// How many dimensions is this reference from the base variable?
// nodep is typically the fromp() of a select; thus the first select
// is selecting from the entire variable type - effectively dimension 0.
// Dimension passed to AstVar::dtypeDimensionp; see comments there
int dim = 0;
while (nodep) {
if (nodep->castNodeSel()) { dim++; nodep=nodep->castNodeSel()->fromp(); continue; }

View File

@ -105,6 +105,31 @@ public:
virtual bool same(AstNode* samep) const { return true; }
};
//######################################################################
//==== Data Types
struct AstArrayDType : public AstNodeDType {
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep)
: AstNodeDType(fl) {
setOp1p(dtypep);
setOp2p(rangep);
widthSignedFrom(dtypep);
}
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstRange* arrayp() const { return op2p()->castRange(); } // op2 = Array(s) of variable
void arrayp(AstRange* nodep) { setOp2p(nodep); }
// METHODS
virtual AstBasicDType* basicp() { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * dtypep()->widthTotalBytes(); }
int msb() const { return arrayp()->msbConst(); }
int lsb() const { return arrayp()->lsbConst(); }
int elementsConst() const { return arrayp()->elementsConst(); }
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
};
struct AstBasicDType : public AstNodeDType {
// Builtin atomic/vectored data type
private:
@ -112,11 +137,17 @@ private:
bool m_implicit; // Implicitly declared
public:
AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstRange* rangep=NULL, AstSignedState signst=signedst_NOP)
: AstNodeDType(fl), m_keyword(kwd) {
init(signst, rangep);
: AstNodeDType(fl) {
init(kwd, signst, rangep);
}
AstBasicDType(FileLine* fl, AstLogicPacked, int wantwidth)
: AstNodeDType(fl) {
init(AstBasicDTypeKwd::LOGIC, signedst_NOP,
((wantwidth > 1) ? new AstRange(fl, wantwidth-1, 0) : NULL));
}
private:
void init(AstSignedState signst, AstRange* rangep) {
void init(AstBasicDTypeKwd kwd, AstSignedState signst, AstRange* rangep) {
m_keyword = kwd;
// Implicitness: // "parameter X" is implicit and sized from initial value, "parameter reg x" not
m_implicit = false;
if (keyword()==AstBasicDTypeKwd::LOGIC_IMPLICIT) {
@ -148,6 +179,9 @@ public:
if (signst!=signedst_NOP) isSigned(signst==signedst_SIGNED);
}
// METHODS
virtual AstBasicDType* basicp() { return this; } // (Slow) recurse down to find basic data type
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
bool isBitLogic() const { return keyword().isBitLogic(); }
bool isSloppy() const { return keyword().isSloppy(); }
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
@ -159,6 +193,8 @@ public:
bool implicit() const { return m_implicit; }
};
//######################################################################
struct AstArraySel : public AstNodeSel {
// Parents: math|stmt
// Children: varref|arraysel, math
@ -319,21 +355,19 @@ private:
m_trace=false;
}
public:
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtypep, AstRange* arrayp=NULL)
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtypep)
:AstNode(fl)
, m_name(name) {
init();
combineType(type); setOp1p(dtypep); addNOp2p(arrayp);
combineType(type); setOp1p(dtypep);
width(msb()-lsb()+1,0);
}
class LogicPacked {};
AstVar(FileLine* fl, AstVarType type, const string& name, LogicPacked, int wantwidth)
AstVar(FileLine* fl, AstVarType type, const string& name, AstLogicPacked, int wantwidth)
:AstNode(fl)
, m_name(name) {
init();
combineType(type);
setOp1p(new AstBasicDType(fl, AstBasicDTypeKwd::LOGIC,
((wantwidth > 1) ? new AstRange(fl, wantwidth-1, 0) : NULL)));
setOp1p(new AstBasicDType(fl, AstLogicPacked(), wantwidth));
width(wantwidth,0);
}
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
@ -344,9 +378,6 @@ public:
if (examplep->dtypep()) {
setOp1p(examplep->dtypep()->cloneTree(true));
}
if (examplep->arraysp()) {
setOp2p(examplep->arraysp()->cloneTree(true));
}
width(examplep->width(), examplep->widthMin());
}
ASTNODE_NODE_FUNCS(Var, VAR)
@ -361,9 +392,7 @@ public:
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
void combineType(AstVarType type);
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
AstRange* arraysp() const { return op2p()->castRange(); } // op2 = Array(s) of variable
void addArraysp(AstNode* nodep) { addNOp2p(nodep); }
AstRange* arrayp(int dim) const; // op2 = Range for specific dimension #
AstNodeDType* dtypeDimensionp(int depth) const;
AstNode* initp() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
void initp(AstNode* nodep) { setOp3p(nodep); }
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
@ -387,6 +416,7 @@ public:
void funcReturn(bool flag) { m_funcReturn = flag; }
void trace(bool flag) { m_trace=flag; }
// METHODS
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual void name(const string& name) { m_name = name; }
bool isInput() const { return m_input; }
bool isOutput() const { return m_output; }
@ -411,7 +441,7 @@ public:
bool isParam() const { return (varType()==AstVarType::LPARAM || varType()==AstVarType::GPARAM); }
bool isGParam() const { return (varType()==AstVarType::GPARAM); }
bool isGenVar() const { return (varType()==AstVarType::GENVAR); }
bool isBitLogic() const { return dtypep()->castBasicDType() && dtypep()->castBasicDType()->isBitLogic(); }
bool isBitLogic() const { AstBasicDType* bdtypep = basicp(); return bdtypep && bdtypep->isBitLogic(); }
bool isUsedClock() const { return m_usedClock; }
bool isUsedParam() const { return m_usedParam; }
bool isSc() const { return m_sc; }
@ -429,15 +459,11 @@ public:
bool attrFileDescr() const { return m_fileDescr; }
bool attrScClocked() const { return m_scClocked; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
int widthAlignBytes() const; // Structure alignment 1,2,4 or 8 bytes (arrays affect this)
int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,...
int msb() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->msb(); }
int lsb() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->lsb(); }
int msbEndianed() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->msbEndianed(); }
int lsbEndianed() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->lsbEndianed(); }
int msbMaxSelect() const { if (!dtypep()) return 0; return dtypep()->castBasicDType()->msbMaxSelect(); }
bool littleEndian() const { return (dtypep() && dtypep()->castBasicDType()->littleEndian()); }
int arrayDimensions() const;
int msb() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->msb() : 0; }
int lsb() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->lsb() : 0; }
int msbEndianed() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->msbEndianed() : 0; }
int lsbEndianed() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->lsbEndianed() : 0; }
int msbMaxSelect() const { AstBasicDType* bdtypep = basicp(); return bdtypep ? bdtypep->msbMaxSelect() : 0; }
uint32_t arrayElements() const; // 1, or total multiplication of all dimensions
virtual string verilogKwd() const;
void propagateAttrFrom(AstVar* fromp) {
@ -1695,8 +1721,13 @@ public:
m_code = 0;
m_codeInc = varp->arrayElements() * varp->widthWords();
m_lsb = varp->lsbEndianed(); m_msb = varp->msbEndianed();
m_arrayLsb = varp->arrayp(0) ? varp->arrayp(0)->lsbConst() : 0;
m_arrayMsb = varp->arrayp(0) ? varp->arrayp(0)->msbConst() : 0;
if (AstArrayDType* adtypep = varp->dtypep()->castArrayDType()) {
m_arrayLsb = adtypep->arrayp()->lsbConst();
m_arrayMsb = adtypep->arrayp()->msbConst();
} else {
m_arrayLsb = 0;
m_arrayMsb = 0;
}
}
virtual int instrCount() const { return 100; } // Large...
ASTNODE_NODE_FUNCS(TraceDecl, TRACEDECL)

View File

@ -157,7 +157,7 @@ private:
// Note var can be signed or unsigned based on original number.
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, AstVar::LogicPacked(), countp->width());
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), countp->width());
m_modp->addStmtp(varp);
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
countp);

View File

@ -72,7 +72,7 @@ private:
#endif
AstVar* varp = vscp->varp();
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
if (varp->arraysp()) {
if (!varp->dtypep()->castBasicDType()) {
vscp->v3error("Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
} else {
string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();

View File

@ -76,7 +76,7 @@ private:
}
void computeCppWidth (AstNode* nodep) {
if (!nodep->user2()) {
if (nodep->castVar()) { // Don't want to change variable widths!
if (nodep->castVar() || nodep->castNodeDType()) { // Don't want to change variable widths!
setCppWidth(nodep, nodep->width(), nodep->width()); // set widthMin anyways so can see it later
} else {
setCppWidth(nodep, cppWidth(nodep), nodep->widthMin());

View File

@ -85,7 +85,7 @@ private:
AstVar* varp = vscp->varp();
if (varp->width()!=1) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName());
AstVar* newvarp = new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, AstVar::LogicPacked(), 1);
AstVar* newvarp = new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, AstLogicPacked(), 1);
newvarp->width(1,1);
m_modp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
@ -104,7 +104,7 @@ private:
AstVarScope* getCreateLocalVar(FileLine* fl, const string& name, AstVar* examplep, int width) {
AstVar* newvarp;
if (width) {
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, AstVar::LogicPacked(), width);
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, AstLogicPacked(), width);
} else {
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, examplep); // No range; 1 bit.
}

View File

@ -306,14 +306,14 @@ private:
// Extraction checks
bool warnSelect(AstSel* nodep) {
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
AstNode* basefromp = AstArraySel::baseFromp(nodep);
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
AstVar* varp = varrefp->varp();
if (!varp->dtypep()) varp->v3fatalSrc("Data type lost");
if (m_warn
&& nodep->lsbp()->castConst()
&& nodep->widthp()->castConst()
&& (!varp->dtypep()->rangep() || varp->msb())) { // else it's non-resolvable parameterized
&& (!varp->basicp()->rangep() || varp->msb())) { // else it's non-resolvable parameterized
if (nodep->lsbp()->castConst()->num().isFourState()
|| nodep->widthp()->castConst()->num().isFourState()) {
nodep->v3error("Selection index is constantly unknown or tristated: "
@ -771,9 +771,9 @@ private:
string name1 = ((string)"__Vconcswap"+cvtToStr(m_modp->varNumGetInc()));
string name2 = ((string)"__Vconcswap"+cvtToStr(m_modp->varNumGetInc()));
AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1,
AstVar::LogicPacked(), msb1-lsb1+1);
AstLogicPacked(), msb1-lsb1+1);
AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2,
AstVar::LogicPacked(), msb2-lsb2+1);
AstLogicPacked(), msb2-lsb2+1);
m_modp->addStmtp(temp1p);
m_modp->addStmtp(temp2p);
AstNodeAssign* asn1ap=nodep->cloneType

View File

@ -48,6 +48,19 @@ private:
// TYPES
typedef map<string,int> FileMap;
struct ToggleEnt {
string m_comment; // Comment for coverage dump
AstNode* m_varRefp; // How to get to this element
AstNode* m_chgRefp; // How to get to this element
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
: m_comment(comment), m_varRefp(vp), m_chgRefp(cp) {}
~ToggleEnt() {}
void cleanup() {
m_varRefp->deleteTree(); m_varRefp=NULL;
m_chgRefp->deleteTree(); m_chgRefp=NULL;
}
};
// STATE
bool m_checkBlock; // Should this block get covered?
AstModule* m_modp; // Current module to add statement to
@ -143,12 +156,6 @@ private:
// Convert to "AstCoverInc(CoverInc...)"
// We'll do this, and make the if(...) coverinc later.
// Compute size of the problem
int dimensions = 0;
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
dimensions++;
}
// Add signal to hold the old value
string newvarname = (string)"__Vtogcov__"+nodep->shortName();
AstVar* chgVarp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
@ -157,61 +164,65 @@ private:
// Create bucket for each dimension * bit.
// This is necessarily an O(n^2) expansion, which is why
// we limit coverage to signals with < 256 bits.
vector<int> selects_docs; selects_docs.resize(dimensions);
vector<int> selects_code; selects_code.resize(dimensions);
toggleVarRecurse(nodep, chgVarp, nodep->arraysp(),
0, selects_docs, selects_code );
ToggleEnt newvec (string(""),
new AstVarRef(nodep->fileline(), nodep, false),
new AstVarRef(nodep->fileline(), chgVarp, true));
toggleVarRecurse(nodep->dtypep(), 0, newvec,
nodep, chgVarp);
newvec.cleanup();
}
}
}
void toggleVarRecurse(AstVar* nodep, AstVar* chgVarp, AstRange* arrayp,
int dimension, vector<int>& selects_docs, vector<int>& selects_code) {
if (arrayp) {
for (int index=arrayp->lsbConst(); index<=arrayp->msbConst()+1; index++) {
// Handle the next dimension, if any
selects_docs[dimension] = index;
selects_code[dimension] = index - arrayp->lsbConst();
toggleVarRecurse(nodep, chgVarp, arrayp->nextp()->castRange(),
dimension+1, selects_docs, selects_code);
}
} else { // No more arraying - just each bit in the width
if (nodep->msb() != nodep->lsb()) {
for (int bitindex_docs=nodep->lsb(); bitindex_docs<nodep->msb()+1; bitindex_docs++) {
toggleVarBottom(nodep, chgVarp,
dimension, selects_docs, selects_code,
true, bitindex_docs);
void toggleVarBottom(AstNodeDType* nodep, int depth, // per-iteration
const ToggleEnt& above,
AstVar* varp, AstVar* chgVarp) { // Constant
AstCoverToggle* newp
= new AstCoverToggle (varp->fileline(),
newCoverInc(varp->fileline(), "", "v_toggle",
varp->name()+above.m_comment),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true));
m_modp->addStmtp(newp);
}
void toggleVarRecurse(AstNodeDType* nodep, int depth, // per-iteration
const ToggleEnt& above,
AstVar* varp, AstVar* chgVarp) { // Constant
if (AstBasicDType* bdtypep = nodep->castBasicDType()) {
if (bdtypep->rangep()) {
for (int index_docs=bdtypep->lsb(); index_docs<bdtypep->msb()+1; index_docs++) {
int index_code = index_docs - bdtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code, 1),
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code, 1));
toggleVarBottom(nodep, depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
} else {
toggleVarBottom(nodep, chgVarp,
dimension, selects_docs, selects_code,
false, 0);
toggleVarBottom(nodep, depth+1,
above,
varp, chgVarp);
}
}
}
void toggleVarBottom(AstVar* nodep, AstVar* chgVarp,
int dimension, vector<int>& selects_docs, vector<int>& selects_code,
bool bitsel, int bitindex_docs) {
string comment = nodep->name();
AstNode* varRefp = new AstVarRef(nodep->fileline(), nodep, false);
AstNode* chgRefp = new AstVarRef(nodep->fileline(), chgVarp, true);
// Now determine the name of, and how to get to the bit of this slice
for (int dim=0; dim<dimension; dim++) {
// Comments are strings, not symbols, so we don't need __BRA__ __KET__
comment += "["+cvtToStr(selects_docs[dim])+"]";
varRefp = new AstArraySel(nodep->fileline(), varRefp, selects_code[dim]);
chgRefp = new AstArraySel(nodep->fileline(), chgRefp, selects_code[dim]);
else if (AstArrayDType* adtypep = nodep->castArrayDType()) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) {
int index_code = index_docs - adtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
new AstArraySel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code),
new AstArraySel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code));
toggleVarRecurse(adtypep->dtypep(), depth+1,
newent,
varp, chgVarp);
newent.cleanup();
}
}
if (bitsel) {
comment += "["+cvtToStr(bitindex_docs)+"]";
int bitindex_code = bitindex_docs - nodep->lsb();
varRefp = new AstSel(nodep->fileline(), varRefp, bitindex_code, 1);
chgRefp = new AstSel(nodep->fileline(), chgRefp, bitindex_code, 1);
else {
nodep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<<nodep->prettyTypeName());
}
AstCoverToggle* newp = new AstCoverToggle (nodep->fileline(),
newCoverInc(nodep->fileline(), "", "v_toggle", comment),
varRefp, chgRefp);
m_modp->addStmtp(newp);
}
// VISITORS - LINE COVERAGE

View File

@ -132,7 +132,7 @@ private:
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
varp->widthSignedFrom(oldvarscp);
} else {
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, AstVar::LogicPacked(), width);
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), width);
}
addmodp->addStmtp(varp);
m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp));

View File

@ -68,7 +68,7 @@ private:
// Width, not widthMin, as we may be in middle of BITSEL expression which
// though it's one bit wide, needs the mask in the upper bits.
// (Someday we'll have a valid bitmask instead of widths....)
AstVar::LogicPacked(), nodep->width());
AstLogicPacked(), nodep->width());
if (!m_funcp) nodep->v3fatalSrc("Deep expression not under a function");
m_funcp->addInitsp(varp);
// Replace node tree with reference to var

View File

@ -274,10 +274,13 @@ public:
uint32_t array_lsb = 0;
{
AstVarRef* varrefp = nodep->memp()->castVarRef();
if (!varrefp || !varrefp->varp()->arrayp(0)) { nodep->v3error("Readmem loading non-arrayed variable"); }
else {
if (!varrefp) { nodep->v3error("Readmem loading non-variable"); }
else if (AstArrayDType* adtypep = varrefp->varp()->dtypep()->castArrayDType()) {
puts(cvtToStr(varrefp->varp()->arrayElements()));
array_lsb = varrefp->varp()->arrayp(0)->lsbConst();
array_lsb = adtypep->lsb();
}
else {
nodep->v3error("Readmem loading non-arrayed variable");
}
}
putbs(", ");
@ -770,7 +773,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
puts(nodep->name());
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes());
ofp()->putAlign(nodep->isStatic(), nodep->dtypep()->widthAlignBytes(),
nodep->dtypep()->widthTotalBytes());
if (nodep->isInout()) puts("VL_INOUT");
else if (nodep->isInput()) puts("VL_IN");
else if (nodep->isOutput()) puts("VL_OUT");
@ -793,7 +797,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
} else {
// Arrays need a small alignment, but may need different padding after.
// For example three VL_SIG8's needs alignment 1 but size 3.
ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes(), nodep->arrayElements()*nodep->widthAlignBytes());
ofp()->putAlign(nodep->isStatic(), nodep->dtypep()->widthAlignBytes(),
nodep->dtypep()->widthTotalBytes());
if (nodep->isStatic() && prefixIfImp=="") puts("static ");
if (nodep->isStatic()) puts("VL_ST_"); else puts("VL_");
if (nodep->widthMin() <= 8) {
@ -809,7 +814,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
}
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
puts(nodep->name());
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=nodep->dtypep()->castArrayDType(); arrayp; arrayp = arrayp->dtypep()->castArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
puts(","+cvtToStr(nodep->msb())+","+cvtToStr(nodep->lsb()));
@ -1154,18 +1160,22 @@ void EmitCImp::emitVarResets(AstModule* modp) {
}
else if (AstInitArray* initarp = varp->initp()->castInitArray()) {
AstConst* constsp = initarp->initsp()->castConst();
if (!varp->arraysp()) varp->v3fatalSrc("InitArray under non-arrayed var");
for (int i=0; i<varp->arraysp()->elementsConst(); i++) {
if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement");
emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp);
constsp = constsp->nextp()->castConst();
if (AstArrayDType* arrayp = varp->dtypep()->castArrayDType()) {
for (int i=0; i<arrayp->elementsConst(); i++) {
if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement");
emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp);
constsp = constsp->nextp()->castConst();
}
} else {
varp->v3fatalSrc("InitArray under non-arrayed var");
}
}
else {
int vects = 0;
for (AstRange* arrayp=varp->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=varp->dtypep()->castArrayDType(); arrayp; arrayp = arrayp->dtypep()->castArrayDType()) {
int vecnum = vects++;
if (arrayp->msbConst() < arrayp->lsbConst()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
string ivar = string("__Vi")+cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";");
@ -1413,15 +1423,16 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
}
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
if (doit) {
int sigbytes = varp->widthAlignBytes();
if (varp->isUsedClock() && varp->widthMin()==1) sigbytes = 0;
else if (varp->arraysp()) sigbytes=7;
else if (varp->isScBv()) sigbytes=6;
else if (sigbytes==8) sigbytes=5;
else if (sigbytes==4) sigbytes=4;
else if (sigbytes==2) sigbytes=2;
else if (sigbytes==1) sigbytes=1;
if (size==sigbytes) {
int sigbytes = varp->dtypep()->widthAlignBytes();
int sortbytes = 7;
if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0;
else if (varp->dtypep()->castArrayDType()) sortbytes=7;
else if (varp->isScBv()) sortbytes=6;
else if (sigbytes==8) sortbytes=5;
else if (sigbytes==4) sortbytes=4;
else if (sigbytes==2) sortbytes=2;
else if (sigbytes==1) sortbytes=1;
if (size==sortbytes) {
emitVarDecl(varp, prefixIfImp);
}
}
@ -1889,7 +1900,8 @@ class EmitCTrace : EmitCStmts {
puts("(");
if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP(");
varrefp->iterate(*this); // Put var name out
if (varp->arraysp()) {
// Tracing only supports 1D arrays
if (varp->dtypep()->castArrayDType()) {
if (arrayindex==-2) puts("[i]");
else if (arrayindex==-1) puts("[0]");
else puts("["+cvtToStr(arrayindex)+"]");

View File

@ -423,11 +423,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
if (nodep->isSigned()) puts("signed ");
nodep->dtypep()->iterateChildren(*this);
puts(nodep->name());
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
puts(" ["+cvtToStr(arrayp->msbConst())
+":"+cvtToStr(arrayp->lsbConst())
+"]");
}
puts(";\n");
}
virtual void visit(AstNodeText*, AstNUser*) {}

View File

@ -157,7 +157,7 @@ private:
if (!forrefp->varp()) {
if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
forrefp->name(), AstVar::LogicPacked(), 1);
forrefp->name(), AstLogicPacked(), 1);
newp->trace(m_modp->modTrace());
m_modp->addStmtp(newp);

View File

@ -84,8 +84,8 @@ private:
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->arraysp() && nodep->isIO()) {
nodep->v3error("Arrayed variables may not be inputs nor outputs");
if (nodep->isIO() && !nodep->dtypep()->castBasicDType()) {
nodep->v3error("Unsupported: Inputs and outputs must be simple data types; no arrays");
}
if (m_ftaskp) nodep->funcLocal(true);
if (nodep->isSigModPublic()) {
@ -124,7 +124,7 @@ private:
// Make a new temp wire
string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
AstVar* newvarp = new AstVar (sensp->fileline(), AstVarType::MODULETEMP, newvarname,
AstVar::LogicPacked(), 1);
AstLogicPacked(), 1);
// We can't just add under the module, because we may be inside a generate, begin, etc.
// We know a SenItem should be under a SenTree/Always etc, we we'll just hunt upwards
AstNode* addwherep = nodep; // Add to this element's next

View File

@ -103,7 +103,7 @@ private:
AstVar* getBlockTemp(AstNode* nodep) {
string newvarname = ((string)"__Vtemp"+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname,
AstVar::LogicPacked(), nodep->widthMin());
AstLogicPacked(), nodep->widthMin());
m_funcp->addInitsp(varp);
return varp;
}

View File

@ -244,7 +244,7 @@ private:
// We can't have non-delayed assignments with same value on LHS and RHS
// as we don't figure out variable ordering.
// Delayed is OK though, as we'll decode the next state separately.
if (nodep->varp()->arraysp()) clearOptimizable(nodep,"Array references");
if (!nodep->varp()->dtypep()->castBasicDType()) clearOptimizable(nodep,"Array references/not basic");
if (nodep->lvalue()) {
if (m_inDlyAssign) {
if (!(vscp->user1() & VU_LVDLY)) {

View File

@ -94,8 +94,8 @@ private:
nodep->iterateChildren(*this);
if (m_counting) {
if (nodep->isUsedClock()) ++m_statVarClock;
if (nodep->arraysp()) ++m_statVarArray;
if (!nodep->arraysp()) m_statVarBytes += nodep->widthTotalBytes();
if (nodep->dtypep()->castArrayDType()) ++m_statVarArray;
else m_statVarBytes += nodep->dtypep()->widthTotalBytes();
if (int(m_statVarWidths.size()) <= nodep->width()) {
m_statVarWidths.resize(nodep->width()+5);
}
@ -106,7 +106,9 @@ private:
allNodes(nodep);
nodep->iterateChildren(*this);
if (m_counting) {
if (!nodep->varp()->arraysp()) m_statVarScpBytes += nodep->varp()->widthTotalBytes();
if (nodep->varp()->dtypep()->castBasicDType()) {
m_statVarScpBytes += nodep->varp()->dtypep()->widthTotalBytes();
}
}
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {

View File

@ -163,7 +163,7 @@ public:
UINFO(9," SimVARREF "<<nodep<<endl);
AstVarScope* vscp = nodep->varScopep();
if (nodep->lvalue()) {
m_outWidth += nodep->varp()->widthTotalBytes();
m_outWidth += nodep->varp()->dtypep()->widthTotalBytes();
m_outVarps.push_back(vscp);
} else {
// We'll make the table with a separate natural alignment for each
@ -182,16 +182,19 @@ private:
// Index into our table
AstVar* indexVarp = new AstVar (nodep->fileline(), AstVarType::BLOCKTEMP,
"__Vtableidx" + cvtToStr(m_modTables),
AstVar::LogicPacked(), m_inWidth);
AstLogicPacked(), m_inWidth);
m_modp->addStmtp(indexVarp);
AstVarScope* indexVscp = new AstVarScope (indexVarp->fileline(), m_scopep, indexVarp);
m_scopep->addVarp(indexVscp);
// Change it variable
AstVar* chgVarp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
"__Vtablechg" + cvtToStr(m_modTables),
AstVar::LogicPacked(), m_outVarps.size());
chgVarp->addArraysp(new AstRange (nodep->fileline(), VL_MASK_I(m_inWidth), 0));
FileLine* fl = nodep->fileline();
AstVar* chgVarp
= new AstVar (fl, AstVarType::MODULETEMP,
"__Vtablechg" + cvtToStr(m_modTables),
new AstArrayDType (fl,
new AstBasicDType(fl, AstLogicPacked(), m_outVarps.size()),
new AstRange (fl, VL_MASK_I(m_inWidth), 0)));
chgVarp->isConst(true);
chgVarp->initp(new AstInitArray (nodep->fileline(), NULL));
m_modp->addStmtp(chgVarp);
@ -229,11 +232,13 @@ private:
for (deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
AstVarScope* outvscp = *it;
AstVar* outvarp = outvscp->varp();
FileLine* fl = nodep->fileline();
AstVar* tablevarp
= new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
= new AstVar (fl, AstVarType::MODULETEMP,
"__Vtable" + cvtToStr(m_modTables) +"_"+outvarp->name(),
AstVar::LogicPacked(), outvarp->widthMin());
tablevarp->addArraysp(new AstRange (nodep->fileline(), VL_MASK_I(m_inWidth), 0));
new AstArrayDType (fl,
new AstBasicDType(fl, AstLogicPacked(), outvarp->widthMin()),
new AstRange (fl, VL_MASK_I(m_inWidth), 0)));
tablevarp->isConst(true);
tablevarp->isStatic(true);
tablevarp->initp(new AstInitArray (nodep->fileline(), NULL));

View File

@ -313,7 +313,7 @@ private:
if (!activityNumber) activityNumber++; // For simplicity, always create it
int activityBits = VL_WORDS_I(activityNumber)*VL_WORDSIZE; // For tighter code; round to next 32 bit point.
AstVar* newvarp = new AstVar (m_chgFuncp->fileline(), AstVarType::MODULETEMP,
"__Vm_traceActivity", AstVar::LogicPacked(), activityBits);
"__Vm_traceActivity", AstLogicPacked(), activityBits);
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(newvarp->fileline(), m_highScopep, newvarp);
m_highScopep->addVarp(newvscp);

View File

@ -75,7 +75,11 @@ private:
return "Inlined leading underscore";
if (nodep->width() > 256) return "Wide bus > 256 bits";
if (nodep->arrayElements() > 32) return "Wide memory > 32 ents";
if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
if (!(nodep->dtypep()->castBasicDType()
|| (nodep->dtypep()->castArrayDType()
&& nodep->dtypep()->castArrayDType()->dtypep()->castBasicDType()))) {
return "Unsupported: Multi-dimensional array";
}
return NULL;
}

View File

@ -207,7 +207,7 @@ private:
AstVar* enp = new AstVar (outrefp->varp()->fileline(),
AstVarType::MODULETEMP,
outrefp->name() + "__en" + suffix + cvtToStr(m_unique++),
AstVar::LogicPacked(), width);
AstLogicPacked(), width);
enp->varType2Out();
if (enp->width() != enrhsp->width()) {
@ -381,7 +381,7 @@ private:
AstVar* newlhsp = new AstVar(lhsp->fileline(),
AstVarType::MODULETEMP,
lhsp->name()+"__lhs"+cvtToStr(m_unique++),
AstVar::LogicPacked(), w);
AstLogicPacked(), w);
nodep->addStmtp(newlhsp);
// now append this driver to the driver logic.
@ -396,7 +396,7 @@ private:
bitselp = new AstVar(lhsp->fileline(),
AstVarType::MODULETEMP,
lhsp->name()+"__sel"+cvtToStr(m_unique-1),
AstVar::LogicPacked(), ws);
AstLogicPacked(), ws);
//
nodep->addStmtp(bitselp);
nodep->addStmtp(new AstAssignW(lhsp->fileline(),

View File

@ -127,7 +127,7 @@ private:
else {
string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
AstVar::LogicPacked(), prep->width());
AstLogicPacked(), prep->width());
m_modp->addStmtp(varp);
AstNode* abovep = prep->backp(); // Grab above point before loose it w/ next replace
@ -288,7 +288,7 @@ private:
+cvtToStr(m_modp->varNumGetInc()));
AstVar* newvarp
= new AstVar (nodep->fileline(), AstVarType::XTEMP, newvarname,
AstVar::LogicPacked(), nodep->width());
AstLogicPacked(), nodep->width());
m_statUnkVars++;
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
@ -327,7 +327,7 @@ private:
// Guard against reading/writing past end of bit vector array
int maxmsb = 0;
bool lvalue = false;
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
AstNode* basefromp = AstArraySel::baseFromp(nodep);
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
lvalue = varrefp->lvalue();
maxmsb = (varrefp->varp()->width()-1);
@ -382,8 +382,10 @@ private:
int maxmsb = 0;
bool lvalue = false;
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
AstArrayDType* adtypep = varrefp->varp()->dtypeDimensionp(dimension)->castArrayDType();
if (!adtypep) nodep->v3fatalSrc("ArraySel to type without array at same depth");
lvalue = varrefp->lvalue();
maxmsb = (varrefp->varp()->arrayp(dimension)->elementsConst()-1);
maxmsb = adtypep->elementsConst()-1;
} else if (AstConst* lhconstp = basefromp->castConst()) {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
maxmsb = lhconstp->widthMin();

View File

@ -265,6 +265,7 @@ private:
virtual void visit(AstSel* nodep, AstNUser* vup) {
if (vup->c()->prelim()) {
if (debug()>=9) nodep->dumpTree(cout,"-selWidth: ");
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
@ -299,7 +300,7 @@ private:
int frommsb = nodep->fromp()->width() - 1;
int fromlsb = 0;
AstNodeVarRef* varrp = nodep->fromp()->castNodeVarRef();
if (varrp && varrp->varp()->dtypep()->rangep()) { // Selecting a bit from a multibit register
if (varrp && varrp->varp()->basicp()->rangep()) { // Selecting a bit from a multibit register
frommsb = varrp->varp()->msbMaxSelect(); // Corrected for negative lsb
fromlsb = varrp->varp()->lsb();
}
@ -314,6 +315,9 @@ private:
<<(nodep->lsbp()->width()!=nodep->lsbp()->widthMin()
?" or "+cvtToStr(nodep->lsbp()->widthMin()):"")
<<" bits.");
UINFO(1," Related node: "<<nodep<<endl);
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
if (varrp) UINFO(1," Related dtype: "<<varrp->varp()->dtypep()<<endl);
}
if (nodep->lsbp()->castConst() && nodep->msbConst() > frommsb) {
// See also warning in V3Const
@ -322,6 +326,9 @@ private:
nodep->v3error("Selection index out of range: "
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<frommsb<<":"<<fromlsb);
UINFO(1," Related node: "<<nodep<<endl);
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
if (varrp) UINFO(1," Related dtype: "<<varrp->varp()->dtypep()<<endl);
}
// iterate FINAL is two blocks above
widthCheck(nodep,"Extract Range",nodep->lsbp(),selwidth,selwidth,true);
@ -339,28 +346,34 @@ private:
//
int frommsb;
int fromlsb;
if (!varrp->varp()->arrayp(dimension)) {
nodep->v3fatalSrc("Array reference exceeds dimension of array");
}
if (1) { // ARRAY slice extraction
AstNodeDType* ddtypep = varrp->varp()->dtypeDimensionp(dimension);
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
int outwidth = varrp->width(); // Width of variable
frommsb = varrp->varp()->arrayp(dimension)->msbConst();
fromlsb = varrp->varp()->arrayp(dimension)->lsbConst();
frommsb = adtypep->msb();
fromlsb = adtypep->lsb();
if (fromlsb>frommsb) {int t=frommsb; frommsb=fromlsb; fromlsb=t; }
// However, if the lsb<0 we may go negative, so need more bits!
if (fromlsb < 0) frommsb += -fromlsb;
nodep->width(outwidth,outwidth); // Width out = width of array
}
else {
nodep->v3fatalSrc("Array reference exceeds dimension of array");
frommsb = fromlsb = 0;
}
int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,FINAL).p());
if (widthBad(nodep->bitp(),selwidth,selwidth)
&& nodep->bitp()->width()!=32)
&& nodep->bitp()->width()!=32) {
nodep->v3warn(WIDTH,"Bit extraction of array["<<frommsb<<":"<<fromlsb<<"] requires "
<<selwidth<<" bit index, not "
<<nodep->bitp()->width()
<<(nodep->bitp()->width()!=nodep->bitp()->widthMin()
?" or "+cvtToStr(nodep->bitp()->widthMin()):"")
<<" bits.");
UINFO(1," Related node: "<<nodep<<endl);
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
if (varrp) UINFO(1," Related depth: "<<dimension<<" dtype: "<<ddtypep<<endl);
}
widthCheck(nodep,"Extract Range",nodep->bitp(),selwidth,selwidth,true);
}
}
@ -473,6 +486,13 @@ private:
virtual void visit(AstScopeName* nodep, AstNUser* vup) {
// Only used in Displays which don't care....
}
virtual void visit(AstArrayDType* nodep, AstNUser* vup) {
// Lower datatype determines the width
nodep->dtypep()->iterateAndNext(*this,vup);
// But also cleanup array size
nodep->arrayp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->widthFrom(nodep->dtypep());
}
virtual void visit(AstBasicDType* nodep, AstNUser* vup) {
if (nodep->rangep()) {
nodep->rangep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
@ -487,8 +507,6 @@ private:
// We can't skip this step when width()!=0, as creating a AstVar
// with non-constant range gets size 1, not size 0.
int width=1; int mwidth=1;
nodep->arraysp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
// Parameters if implicit untyped inherit from what they are assigned to
AstBasicDType* bdtypep = nodep->dtypep()->castBasicDType();
if (nodep->isParam() && bdtypep && bdtypep->implicit()) {
@ -535,11 +553,9 @@ private:
}
//if (debug()>=9) { nodep->dumpTree(cout," VRin "); nodep->varp()->dumpTree(cout," forvar "); }
// Note genvar's are also entered as integers
AstBasicDType* bdtypep = nodep->varp()->dtypep()->castBasicDType();
if (bdtypep && bdtypep->isSloppy()
&& nodep->backp()->castNodeAssign()) { // On LHS
// Consider Integers on LHS to sized (else would be unsized.)
nodep->width(bdtypep->width(),bdtypep->width());
if (nodep->backp()->castNodeAssign() && nodep->lvalue()) { // On LHS
// Consider Integers on LHS to sized (else may be unsized.)
nodep->width(nodep->varp()->width(), nodep->varp()->width());
} else {
nodep->widthFrom(nodep->varp());
}

View File

@ -74,22 +74,29 @@ private:
}
}
void selCheckDimension(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
AstNodeDType* dtypeForExtractp(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
// Perform error checks on the node
AstVar* varp = varFromBasefrom(basefromp);
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: ");
int dimensions = varp->arrayDimensions();
if (dimension < dimensions) {
AstNodeDType* ddtypep = varp->dtypeDimensionp(dimension);
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
if (rangedSelect) {
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
return NULL;
}
} else if (dimension > dimensions) { // Too many indexes provided
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
} else if (dimension == dimensions) { // Right number, but...
if (!varp->dtypep()->rangep()) {
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
}
return adtypep;
}
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (!adtypep->rangep()) {
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
return NULL;
}
return adtypep;
}
else {
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
}
return NULL;
}
AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
@ -133,14 +140,14 @@ private:
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
AstVar* varp = varFromBasefrom(basefromp);
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
if (!varp->dtypep()->rangep()) {
if (!varp->basicp()->rangep()) {
// vector without range is ok, for example a INTEGER x; y = x[21:0];
return underp;
} else {
if (!varp->dtypep()->rangep()->msbp()->castConst()
|| !varp->dtypep()->rangep()->lsbp()->castConst())
if (!varp->basicp()->rangep()->msbp()->castConst()
|| !varp->basicp()->rangep()->lsbp()->castConst())
varp->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(varp)
if (varp->dtypep()->rangep()->littleEndian()) {
if (varp->basicp()->rangep()->littleEndian()) {
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
AstNode* newp = newSubNeg(varp->msb(), underp);
return newp;
@ -169,8 +176,7 @@ private:
// So, see if we're sitting under a variable's arrayp.
AstNode* huntbackp = nodep;
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
if (huntbackp->backp()->castVar()
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
if (huntbackp->backp()->castArrayDType()) {
} else {
// Little endian bits are legal, just remember to swap
// Warning is in V3Width to avoid false warnings when in "off" generate if's
@ -189,26 +195,23 @@ private:
// lhsp/rhsp do not need to be constant
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
selCheckDimension(nodep, basefromp, dimension, false);
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, false);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
AstVar* varp = varFromBasefrom(basefromp);
if (debug()>=9) nodep->dumpTree(cout,"-vsbmd: ");
if (varp->arrayp(dimension)) {
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstRange* arrayp = varp->arrayp(dimension); // NULL checked above
AstNode* subp = bitp;
if (!arrayp->lsbp()->isZero() || arrayp->msbConst()<0) {
subp = newSubNeg (subp, arrayp->lsbConst());
if (adtypep->lsb()!=0 || adtypep->msb()<0) {
subp = newSubNeg (subp, adtypep->lsb());
}
AstArraySel* newp = new AstArraySel
(nodep->fileline(),
fromp,
subp);
AstArraySel* newp = new AstArraySel (nodep->fileline(),
fromp, subp);
UINFO(6," newd"<<dimension<<" "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else {
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (adtypep) {} // unused
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
@ -218,6 +221,11 @@ private:
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension");
// How to recover? We'll strip a dimension.
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstSelExtract* nodep, AstNUser*) {
@ -238,25 +246,33 @@ private:
AstVar* varp = varFromBasefrom(basefromp);
vlsint32_t msb = msbp->castConst()->toSInt();
vlsint32_t lsb = lsbp->castConst()->toSInt();
selCheckDimension(nodep, basefromp, dimension, msb!=lsb);
if (varp->dtypep()->rangep() && varp->dtypep()->rangep()->littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, msb!=lsb);
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (adtypep) {} // Unused
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
}
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
msb +1-lsb);
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(lsbp, basefromp),
widthp);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
pushDeletep(msbp); msbp=NULL;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal range select; variable already selected, or bad dimension");
// How to recover? We'll strip a dimension.
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
}
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
msb +1-lsb);
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(lsbp, basefromp),
widthp);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
pushDeletep(msbp); msbp=NULL;
}
void replaceSelPlusMinus(AstNodePreSel* nodep) {
@ -274,41 +290,49 @@ private:
AstVar* varp = varFromBasefrom(basefromp);
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
selCheckDimension(nodep, basefromp, dimension, width!=1);
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (varp->dtypep()->rangep() && varp->dtypep()->rangep()->littleEndian()) {
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg((varp->msb()-width+1), rhsp),
widthp);
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, width!=1);
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (adtypep) {} // Unused
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg((varp->msb()-width+1), rhsp),
widthp);
} else {
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
widthp);
}
} else if (nodep->castSelMinus()) {
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(varp->msb(), rhsp),
widthp);
} else {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(rhsp, varp->lsb()+(width-1)),
widthp);
}
} else {
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
widthp);
nodep->v3fatalSrc("Bad Case");
}
} else if (nodep->castSelMinus()) {
if (varp->dtypep()->rangep() && varp->dtypep()->rangep()->littleEndian()) {
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(varp->msb(), rhsp),
widthp);
} else {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(rhsp, varp->lsb()+(width-1)),
widthp);
}
} else {
nodep->v3fatalSrc("Bad Case");
UINFO(6," new "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal +: or -: select; variable already selected, or bad dimension");
// How to recover? We'll strip a dimension.
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
}
UINFO(6," new "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelPlus* nodep, AstNUser*) {
replaceSelPlusMinus(nodep);

View File

@ -2613,9 +2613,21 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
if (type == AstVarType::GENVAR) {
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
}
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
AstNodeDType* arrayDTypep = dtypep;
if (arrayp) {
while (arrayp->nextp()) arrayp = arrayp->nextp()->castRange();
while (arrayp) {
AstRange* prevp = arrayp->backp()->castRange();
if (prevp) arrayp->unlinkFrBack();
arrayDTypep = new AstArrayDType(arrayp->fileline(), arrayDTypep, arrayp);
arrayp = prevp;
}
}
AstVar* nodep = new AstVar(fileline, type, name,
dtypep,
arrayp);
arrayDTypep);
nodep->addAttrsp(attrsp);
if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl);
if (GRAMMARP->m_varIO != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varIO);

View File

@ -11,7 +11,7 @@ compile (
fails=>$Self->{v3},
nc=>0,
expect=>
'%Error: t/t_mem_multi_io_bad.v:\d+: Arrayed variables may not be inputs nor outputs
'%Error: t/t_mem_multi_io_bad.v:\d+: Unsupported: Inputs and outputs must be simple data types; no arrays
%Error: Exiting due to.*',
);

View File

@ -11,13 +11,13 @@ compile (
fails=>$Self->{v3},
nc=>0, # Need to get it not to give the prompt
expect=>
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dimn
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dimn
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim1
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim0nv
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dim0nv
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0nv
.*%Error: Exiting due to.*},
);

View File

@ -40,6 +40,7 @@ module t (/*AUTOARG*/
end
reg [71:0] wread;
reg wreadb;
always @ (posedge clk) begin
//$write("cyc==%0d crc=%x i[%d][%d][%d] nar=%x wide=%x\n",cyc, crc, index0,index1,index2, narrow, wide);
@ -58,12 +59,14 @@ module t (/*AUTOARG*/
index1 <= crc[3:2];
index2 <= crc[6:4];
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
// We never read past bounds, or get unspecific results
// We also never read lowest indexes, as writing outside of range may corrupt them
if (index0>=0+1 && index0<=2 && index1>=1+1 && index1<=3 && index2>=2+1 && index2<=5) begin
narrow <= ({narrow[6:0], narrow[7]^narrow[0]}
^ {memn[index0][index1][index2]});
wread = memw[index0][index1][index2];
wreadb = memw[index0][index1][index2][2];
wide <= ({wide[70:0], wide[71]^wide[2]^wide[0]} ^ wread);
//$write("Get memw[%d][%d][%d] -> %x\n",index0,index1,index2, wread);
end

View File

@ -12,6 +12,17 @@ module t (
little little (.clk(CLK));
glbl glbl ();
// A vector
logic [2:1] vec [4:3];
integer val = 0;
always @ (posedge CLK) begin
if (RESET) val <= 0;
else val <= val + 1;
vec[3] <= val[1:0];
vec[4] <= val[3:2];
end
initial RESET = 1'b1;
always @ (posedge CLK)
RESET <= glbl.GSR;

View File

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

View File

@ -21,7 +21,7 @@ if ($Self->{v3}) {
);
vcd_identical ("$Self->{obj_dir}/simx.vcd",
"t/$Self->{name}.out");
"t/t_trace_public.out");
}
ok(1);

View File

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

View File

@ -21,7 +21,7 @@ if ($Self->{v3}) {
);
vcd_identical ("$Self->{obj_dir}/simx.vcd",
"t/$Self->{name}.out");
"t/t_trace_public.out");
# vcd_identical doesn't detect "$var a.b;" vs "$scope module a; $var b;"
file_grep ("$Self->{obj_dir}/simx.vcd", qr/module glbl/i);
}