mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
MAJOR: Support packed structures and unions, bug181.
This commit is contained in:
parent
aec019991c
commit
6339159b04
3
Changes
3
Changes
@ -9,7 +9,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
concatenates and pullup/pulldowns, bug395, bug56, bug54, bug51.
|
||||
[Alex Solomatnikov, Lane Brooks, et al]
|
||||
|
||||
** Major internal changes to support future complex data types.
|
||||
** Support packed structures and unions, bug181.
|
||||
Note this was a major internal change that may lead to some instability.
|
||||
|
||||
*** Support tri0 and tri1, bug462. [Alex Solomatnikov]
|
||||
|
||||
|
@ -1747,8 +1747,8 @@ Verilator supports ==? and !=? operators, ++ and -- in some contexts,
|
||||
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
|
||||
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
|
||||
const, do-while, enum, export, final, import, int, logic, longint, package,
|
||||
program, shortint, time, typedef, var, void, priority case/if, and unique
|
||||
case/if.
|
||||
program, shortint, struct, time, typedef, union, var, void, priority
|
||||
case/if, and unique case/if.
|
||||
|
||||
It also supports .name and .* interconnection.
|
||||
|
||||
@ -2218,6 +2218,14 @@ Verilator is optimized for edge sensitive (flop based) designs. It will
|
||||
attempt to do the correct thing for latches, but most performance
|
||||
optimizations will be disabled around the latch.
|
||||
|
||||
=head2 Structures and Unions
|
||||
|
||||
Verilator only presently supports packed structs and packed unions. Rand
|
||||
and randc tags on members are simply ignored. All structures and unions
|
||||
are represented as a single vector, which means that generating one member
|
||||
of a structure from blocking, and another from non-blocking assignments is
|
||||
unsupported.
|
||||
|
||||
=head2 Time
|
||||
|
||||
All delays (#) are ignored, as they are in synthesis.
|
||||
|
40
src/V3Ast.h
40
src/V3Ast.h
@ -221,6 +221,8 @@ public:
|
||||
ILLEGAL,
|
||||
EXPR_BITS, // V3Const converts to constant
|
||||
//
|
||||
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked
|
||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||
@ -235,8 +237,8 @@ public:
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"%E-AT", "EXPR_BITS", "VAR_BASE",
|
||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"%E-AT", "EXPR_BITS", "MEMBER_BASE",
|
||||
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT"
|
||||
};
|
||||
@ -1518,6 +1520,40 @@ public:
|
||||
static int uniqueNumInc() { return ++s_uniqueNum; }
|
||||
};
|
||||
|
||||
struct AstNodeClassDType : public AstNodeDType {
|
||||
private:
|
||||
// TYPES
|
||||
typedef map<string,AstMemberDType*> MemberNameMap;
|
||||
// MEMBERS
|
||||
bool m_packed;
|
||||
MemberNameMap m_members;
|
||||
public:
|
||||
AstNodeClassDType(FileLine* fl, AstNumeric numericUnpack)
|
||||
: AstNodeDType(fl) {
|
||||
// AstNumeric::NOSIGN overloaded to indicate not packed
|
||||
m_packed = (numericUnpack != AstNumeric::NOSIGN);
|
||||
numeric(numericUnpack.isSigned() ? AstNumeric::SIGNED : AstNumeric::UNSIGNED);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeClassDType)
|
||||
virtual bool broken() const;
|
||||
virtual void dump(ostream& str);
|
||||
// For basicp() we reuse the size to indicate a "fake" basic type of same size
|
||||
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
|
||||
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||
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,...
|
||||
// op1 = members
|
||||
AstMemberDType* membersp() const { return op1p()->castMemberDType(); } // op1 = AstMember list
|
||||
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
bool packed() const { return m_packed; }
|
||||
void clearCache() { m_members.clear(); }
|
||||
void repairMemberCache();
|
||||
AstMemberDType* findMember(const string& name) const {
|
||||
MemberNameMap::const_iterator it = m_members.find(name);
|
||||
return (it==m_members.end()) ? NULL : it->second;
|
||||
}
|
||||
};
|
||||
|
||||
struct AstNodeSel : public AstNodeBiop {
|
||||
// Single bit range extraction, perhaps with non-constant selection or array selection
|
||||
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
|
@ -46,6 +46,28 @@ int AstNodeSel::bitConst() const {
|
||||
AstConst* constp=bitp()->castConst(); return (constp?constp->toSInt():0);
|
||||
}
|
||||
|
||||
void AstNodeClassDType::repairMemberCache() {
|
||||
clearCache();
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
|
||||
if (m_members.find(itemp->name())!=m_members.end()) { itemp->v3error("Duplicate declaration of member name: "<<itemp->prettyName()); }
|
||||
else m_members.insert(make_pair(itemp->name(), itemp));
|
||||
}
|
||||
}
|
||||
|
||||
bool AstNodeClassDType::broken() const {
|
||||
set<AstMemberDType*> exists;
|
||||
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
|
||||
exists.insert(itemp);
|
||||
}
|
||||
for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) {
|
||||
if (exists.find(it->second) == exists.end()) {
|
||||
this->v3error("Internal: Structure member broken: "<<it->first);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AstBasicDType::widthAlignBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
@ -60,6 +82,22 @@ int AstBasicDType::widthTotalBytes() const {
|
||||
else return widthWords()*(VL_WORDSIZE/8);
|
||||
}
|
||||
|
||||
int AstNodeClassDType::widthTotalBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isQuad()) return 8;
|
||||
else return widthWords()*(VL_WORDSIZE/8);
|
||||
}
|
||||
|
||||
int AstNodeClassDType::widthAlignBytes() const {
|
||||
// Could do max across members but that would be slow,
|
||||
// instead intuit based on total structure size
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (width()<=32) return 4;
|
||||
else return 8;
|
||||
}
|
||||
|
||||
bool AstVar::isSigPublic() const {
|
||||
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
|
||||
}
|
||||
@ -285,6 +323,14 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else if (AstNodeClassDType* adtypep = dtypep->castNodeClassDType()) {
|
||||
if (adtypep->packed()) {
|
||||
if ((dim++) == dimension) {
|
||||
return adtypep;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// Node no ->next in loop; use continue where necessary
|
||||
break;
|
||||
}
|
||||
@ -679,6 +725,10 @@ void AstRefDType::dump(ostream& str) {
|
||||
if (defp()) { str<<" -> "; defp()->dump(str); }
|
||||
else { str<<" -> UNLINKED"; }
|
||||
}
|
||||
void AstNodeClassDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (packed()) str<<" [PACKED]";
|
||||
}
|
||||
void AstNodeDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (generic()) str<<" [GENERIC]";
|
||||
|
@ -471,6 +471,68 @@ public:
|
||||
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
||||
};
|
||||
|
||||
struct AstStructDType : public AstNodeClassDType {
|
||||
AstStructDType(FileLine* fl, AstNumeric numericUnpack)
|
||||
: AstNodeClassDType(fl,numericUnpack) {}
|
||||
ASTNODE_NODE_FUNCS(StructDType, STRUCTDTYPE)
|
||||
virtual string verilogKwd() const { return "struct"; };
|
||||
};
|
||||
|
||||
struct AstUnionDType : public AstNodeClassDType {
|
||||
//UNSUP: bool isTagged;
|
||||
AstUnionDType(FileLine* fl, AstNumeric numericUnpack)
|
||||
: AstNodeClassDType(fl,numericUnpack) {}
|
||||
ASTNODE_NODE_FUNCS(UnionDType, UNIONDTYPE)
|
||||
virtual string verilogKwd() const { return "union"; };
|
||||
};
|
||||
|
||||
struct AstMemberDType : public AstNodeDType {
|
||||
// A member of a struct/union
|
||||
// PARENT: AstClassDType
|
||||
private:
|
||||
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
|
||||
string m_name; // Name of variable
|
||||
int m_lsb; // Within this level's packed struct, the LSB of the first bit of the member
|
||||
//UNSUP: int m_randType; // Randomization type (IEEE)
|
||||
public:
|
||||
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp)
|
||||
: AstNodeDType(fl)
|
||||
, m_name(name), m_lsb(-1) {
|
||||
childDTypep(dtp); // Only for parser
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
refDTypep(NULL);
|
||||
}
|
||||
AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp)
|
||||
: AstNodeDType(fl)
|
||||
, m_name(name), m_lsb(-1) {
|
||||
UASSERT(dtp,"AstMember created with no dtype");
|
||||
refDTypep(dtp);
|
||||
dtypep(this);
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(MemberDType, MEMBERDTYPE)
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
virtual bool hasDType() const { return true; }
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
//
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
virtual AstNodeDType* skipRefp() const { return dtypeSkipRefp(); }
|
||||
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
// METHODS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
int lsb() const { return m_lsb; }
|
||||
void lsb(int lsb) { m_lsb=lsb; }
|
||||
};
|
||||
|
||||
struct AstEnumItem : public AstNode {
|
||||
private:
|
||||
string m_name;
|
||||
@ -699,6 +761,37 @@ struct AstSel : public AstNodeTriop {
|
||||
int msbConst() const { return lsbConst()+widthConst()-1; }
|
||||
};
|
||||
|
||||
struct AstMemberSel : public AstNodeMath {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
private:
|
||||
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
|
||||
string m_name;
|
||||
public:
|
||||
AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name)
|
||||
: AstNodeMath(fl), m_name(name) {
|
||||
setOp1p(fromp);
|
||||
dtypep(NULL); // V3Width will resolve
|
||||
}
|
||||
AstMemberSel(FileLine* fl, AstNode* fromp, AstMemberDType* dtp)
|
||||
: AstNodeMath(fl) {
|
||||
setOp1p(fromp);
|
||||
dtypep(dtp);
|
||||
m_name = dtp->name();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(MemberSel, MEMBERSEL)
|
||||
virtual string name() const { return m_name; }
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
|
||||
V3ERROR_NA; /* How can from be a const? */ }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual bool same(AstNode* samep) const { return true; } // dtype comparison does it all for us
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
};
|
||||
|
||||
struct AstVar : public AstNode {
|
||||
// A variable (in/out/wire/reg/param) inside a module
|
||||
private:
|
||||
|
@ -622,6 +622,7 @@ public:
|
||||
virtual void visit(AstTraceDecl*, AstNUser*) {} // Handled outside the Visit class
|
||||
virtual void visit(AstTraceInc*, AstNUser*) {} // Handled outside the Visit class
|
||||
virtual void visit(AstCFile*, AstNUser*) {} // Handled outside the Visit class
|
||||
virtual void visit(AstTypedef*, AstNUser*) {} // Nothing needed presently
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
puts((string)"\n???? // "+nodep->prettyTypeName()+"\n");
|
||||
|
@ -501,6 +501,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
nodep->subDTypep()->iterateAndNext(*this);
|
||||
nodep->rangep()->iterateAndNext(*this);
|
||||
}
|
||||
virtual void visit(AstNodeClassDType* nodep, AstNUser*) {
|
||||
puts(nodep->verilogKwd()+" ");
|
||||
if (nodep->packed()) puts("packed ");
|
||||
puts("\n");
|
||||
nodep->membersp()->iterateAndNext(*this);
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstMemberDType* nodep, AstNUser*) {
|
||||
nodep->subDTypep()->iterateAndNext(*this);
|
||||
puts(" ");
|
||||
puts(nodep->name());
|
||||
puts("}");
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); }
|
||||
else { putfs(nodep,nodep->prettyName()); }
|
||||
|
@ -1192,7 +1192,11 @@ private:
|
||||
m_dotSymp = m_curSymp;
|
||||
}
|
||||
if (m_dotPos == DP_MEMBER) {
|
||||
nodep->v3error("Unsupported: Structs and dotted reference into variable");
|
||||
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
|
||||
AstNode* varEtcp = m_dotp->lhsp()->unlinkFrBack();
|
||||
AstNode* newp = new AstMemberSel(nodep->fileline(), varEtcp, VFlagChildDType(), nodep->name());
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else {
|
||||
//
|
||||
|
@ -200,10 +200,15 @@ private:
|
||||
// So we replicate it in another node
|
||||
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||
AstNodeVarRef* varrefp = basefromp->castNodeVarRef(); // Maybe varxref - so need to clone
|
||||
if (!varrefp) nodep->v3fatalSrc("Illegal bit select; no signal being extracted from");
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||
varrefp->cloneTree(false)));
|
||||
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { // Maybe varxref - so need to clone
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||
varrefp->cloneTree(false)));
|
||||
} else if (AstMemberSel* fromp = nodep->fromp()->castMemberSel()) {
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::MEMBER_BASE,
|
||||
fromp->cloneTree(false)));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,9 @@ struct V3ParseBisonYYSType {
|
||||
AstCaseItem* caseitemp;
|
||||
AstCell* cellp;
|
||||
AstConst* constp;
|
||||
AstMemberDType* memberp;
|
||||
AstNodeModule* modulep;
|
||||
AstNodeClassDType* classp;
|
||||
AstNodeDType* dtypep;
|
||||
AstNodeFTask* ftaskp;
|
||||
AstNodeFTaskRef* ftaskrefp;
|
||||
|
@ -118,6 +118,7 @@ private:
|
||||
AstNodeCase* m_casep; // Current case statement CaseItem is under
|
||||
AstFunc* m_funcp; // Current function
|
||||
AstInitial* m_initialp; // Current initial block
|
||||
AstAttrOf* m_attrp; // Current attribute
|
||||
bool m_doGenerate; // Do errors later inside generate statement
|
||||
|
||||
// CLASSES
|
||||
@ -377,6 +378,7 @@ private:
|
||||
|
||||
virtual void visit(AstSel* nodep, AstNUser* vup) {
|
||||
// Signed: always unsigned; Real: Not allowed
|
||||
if (nodep->didWidth()) return;
|
||||
if (vup->c()->prelim()) {
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-selWidth: ");
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
|
||||
@ -531,7 +533,6 @@ private:
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
nodep->v3fatalSrc("AstSelExtract should disappear after widthSel");
|
||||
}
|
||||
|
||||
virtual void visit(AstSelPlus* nodep, AstNUser* vup) {
|
||||
nodep->attrp()->iterateAndNext(*this,WidthVP(0,0,FINAL).p());
|
||||
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
|
||||
@ -629,6 +630,8 @@ private:
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||
AstAttrOf* oldAttr = m_attrp;
|
||||
m_attrp = nodep;
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
// Don't iterate children, don't want to lose VarRef.
|
||||
if (nodep->attrType()==AstAttrType::EXPR_BITS) {
|
||||
@ -636,12 +639,15 @@ private:
|
||||
V3Number num (nodep->fileline(), 32, nodep->fromp()->width());
|
||||
nodep->replaceWith(new AstConst(nodep->fileline(), num)); nodep->deleteTree(); nodep=NULL;
|
||||
} else if (nodep->attrType()==AstAttrType::VAR_BASE) {
|
||||
// Soon to be handled in V3LinkWidth SEL generation
|
||||
// Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
|
||||
} else if (nodep->attrType()==AstAttrType::MEMBER_BASE) {
|
||||
// Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
|
||||
} else { // Everything else resolved earlier
|
||||
nodep->dtypeSetLogicSized(32,1,AstNumeric::UNSIGNED); // Approximation, unsized 32
|
||||
UINFO(1,"Missing ATTR type case node: "<<nodep<<endl);
|
||||
nodep->v3fatalSrc("Missing ATTR type case");
|
||||
}
|
||||
m_attrp = oldAttr;
|
||||
}
|
||||
virtual void visit(AstText* nodep, AstNUser* vup) {
|
||||
// Only used in CStmts which don't care....
|
||||
@ -760,8 +766,9 @@ private:
|
||||
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
|
||||
nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
|
||||
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype determined for var");
|
||||
if (nodep->isIO() && !(nodep->dtypeSkipRefp()->castBasicDType() ||
|
||||
nodep->dtypeSkipRefp()->castArrayDType())) {
|
||||
if (nodep->isIO() && !(nodep->dtypeSkipRefp()->castBasicDType()
|
||||
|| nodep->dtypeSkipRefp()->castArrayDType()
|
||||
|| nodep->dtypeSkipRefp()->castNodeClassDType())) {
|
||||
nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
|
||||
}
|
||||
if (nodep->dtypeSkipRefp()->castConstDType()) {
|
||||
@ -913,6 +920,81 @@ private:
|
||||
}
|
||||
nodep->dtypeFrom(nodep->itemp());
|
||||
}
|
||||
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
UINFO(5," NODECLASS "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree("-class-in--");
|
||||
if (!nodep->packed()) nodep->v3error("Unsupported: Unpacked struct/union");
|
||||
nodep->iterateChildren(*this); // First size all members
|
||||
nodep->repairMemberCache();
|
||||
// Determine bit assignments and width
|
||||
nodep->dtypep(nodep);
|
||||
int lsb = 0;
|
||||
int width = 0;
|
||||
// MSB is first, so go backwards
|
||||
AstMemberDType* itemp;
|
||||
for (itemp = nodep->membersp(); itemp && itemp->nextp(); itemp=itemp->nextp()->castMemberDType()) ;
|
||||
for (AstMemberDType* backip; itemp; itemp=backip) {
|
||||
backip = itemp->backp()->castMemberDType();
|
||||
itemp->lsb(lsb);
|
||||
if (nodep->castUnionDType()) {
|
||||
width = max(width, itemp->width());
|
||||
} else {
|
||||
lsb += itemp->width();
|
||||
width += itemp->width();
|
||||
}
|
||||
}
|
||||
nodep->widthForce(width,width); // Signing stays as-is, as parsed from declaration
|
||||
//if (debug()>=9) nodep->dumpTree("-class-out-");
|
||||
}
|
||||
virtual void visit(AstMemberDType* nodep, AstNUser* vup) {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
|
||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
|
||||
nodep->dtypep(nodep); // The member itself, not subDtype
|
||||
nodep->widthFromSub(nodep->subDTypep());
|
||||
}
|
||||
virtual void visit(AstMemberSel* nodep, AstNUser* vup) {
|
||||
UINFO(5," MEMBERSEL "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree("-ms-in-");
|
||||
nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
// Find the fromp dtype - should be a class
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp();
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
AstNodeClassDType* fromClassp = fromDtp->castNodeClassDType();
|
||||
AstMemberDType* memberp = NULL; // NULL=error below
|
||||
if (!fromClassp) {
|
||||
nodep->v3error("Member selection of non-struct/union object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
}
|
||||
else {
|
||||
// No need to width-resolve the fromClassp, as it was done when we did the child
|
||||
memberp = fromClassp->findMember(nodep->name());
|
||||
if (!memberp) {
|
||||
nodep->v3error("Member '"<<nodep->prettyName()<<"' not found in structure");
|
||||
}
|
||||
}
|
||||
if (memberp) {
|
||||
if (m_attrp) { // Looking for the base of the attribute
|
||||
nodep->dtypep(memberp);
|
||||
UINFO(9," MEMBERSEL(attr) -> "<<nodep<<endl);
|
||||
} else {
|
||||
AstSel* newp = new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
memberp->lsb(), memberp->width());
|
||||
newp->dtypep(memberp);
|
||||
newp->didWidth(true); // Don't replace dtype with basic type
|
||||
UINFO(9," MEMBERSEL -> "<<newp<<endl);
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
// Should be able to treat it as a normal-ish nodesel - maybe. The lhsp() will be strange until this stage; create the number here?
|
||||
}
|
||||
}
|
||||
if (!memberp) { // Very bogus, but avoids core dump
|
||||
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse()));
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPslClocked* nodep, AstNUser*) {
|
||||
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
nodep->sensesp()->iterateAndNext(*this);
|
||||
@ -2117,6 +2199,7 @@ public:
|
||||
m_casep = NULL;
|
||||
m_funcp = NULL;
|
||||
m_initialp = NULL;
|
||||
m_attrp = NULL;
|
||||
m_doGenerate = doGenerate;
|
||||
}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
|
@ -113,6 +113,13 @@ private:
|
||||
editDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep, AstNUser*) {
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeClassDType* nodep, AstNUser*) {
|
||||
visitIterateNodeDType(nodep);
|
||||
nodep->clearCache();
|
||||
}
|
||||
void visitIterateNodeDType(AstNodeDType* nodep) {
|
||||
// Rather than use dtypeChg which may make new nodes, we simply edit in place,
|
||||
// as we don't need to preserve any widthMin's, and every dtype with the same width
|
||||
// gets an identical edit.
|
||||
|
@ -85,6 +85,9 @@ private:
|
||||
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
||||
return adtypep;
|
||||
}
|
||||
else if (AstNodeClassDType* adtypep = ddtypep->castNodeClassDType()) {
|
||||
return adtypep;
|
||||
}
|
||||
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (!adtypep->isRanged()) {
|
||||
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<errp->prettyName());
|
||||
@ -136,13 +139,21 @@ private:
|
||||
|
||||
AstNodeDType* baseDTypeFrom(AstNode* basefromp, AstNode*& errpr) {
|
||||
errpr = basefromp;
|
||||
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
|
||||
if (!varrefp) basefromp->v3fatalSrc("Bit/array selection of non-variable");
|
||||
AstVar* varp = varrefp->varp(); if (!varp) { varrefp->v3fatalSrc("Signal not linked"); return NULL; }
|
||||
errpr = varp;
|
||||
AstNodeDType* bfdtypep = varp->subDTypep();
|
||||
if (!bfdtypep) basefromp->v3fatalSrc("No datatype found for variable in select");
|
||||
return bfdtypep;
|
||||
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
|
||||
AstVar* varp = varrefp->varp(); if (!varp) { varrefp->v3fatalSrc("Signal not linked"); return NULL; }
|
||||
errpr = varp;
|
||||
AstNodeDType* bfdtypep = varp->subDTypep();
|
||||
if (!bfdtypep) basefromp->v3fatalSrc("No datatype found for variable in select");
|
||||
return bfdtypep;
|
||||
} else if (AstMemberSel* selp = basefromp->castMemberSel()) {
|
||||
errpr = selp;
|
||||
AstNodeDType* bfdtypep = selp->dtypep();
|
||||
if (!bfdtypep) basefromp->v3fatalSrc("No datatype found for variable in select");
|
||||
return bfdtypep;
|
||||
} else {
|
||||
basefromp->v3fatalSrc("Bit/array selection of non-variable");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AstNode* newSubLsbOf(AstNode* underp, AstNode* basefromp) {
|
||||
@ -235,6 +246,17 @@ private:
|
||||
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
else if (AstNodeClassDType* adtypep = ddtypep->castNodeClassDType()) {
|
||||
if (adtypep) {} // unused
|
||||
// SELBIT(range, index) -> SEL(array, index, 1)
|
||||
AstSel* newp = new AstSel (nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(rhsp, basefromp),
|
||||
// Unsized so width from user
|
||||
new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
|
||||
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.
|
||||
@ -292,6 +314,22 @@ private:
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
} else if (AstNodeClassDType* adtypep = ddtypep->castNodeClassDType()) {
|
||||
if (adtypep) {} // Unused
|
||||
// Classes aren't little endian
|
||||
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;
|
||||
}
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal range select; variable already selected, or bad dimension");
|
||||
|
@ -419,13 +419,17 @@ word [a-zA-Z0-9_]+
|
||||
"logic" { FL; return yLOGIC; }
|
||||
"longint" { FL; return yLONGINT; }
|
||||
"package" { FL; return yPACKAGE; }
|
||||
"packed" { FL; return yPACKED; }
|
||||
"priority" { FL; return yPRIORITY; }
|
||||
"program" { FL; return yPROGRAM; }
|
||||
"pure" { FL; return yPURE; }
|
||||
"rand" { FL; return yRAND; }
|
||||
"randc" { FL; return yRANDC; }
|
||||
"return" { FL; return yRETURN; }
|
||||
"shortint" { FL; return ySHORTINT; }
|
||||
"static" { FL; return ySTATIC; }
|
||||
"string" { FL; return ySTRING; }
|
||||
"struct" { FL; return ySTRUCT; }
|
||||
"timeprecision" { FL; return yTIMEPRECISION; }
|
||||
"timeunit" { FL; return yTIMEUNIT; }
|
||||
"typedef" { FL; return yTYPEDEF; }
|
||||
@ -467,17 +471,13 @@ word [a-zA-Z0-9_]+
|
||||
"modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"packed" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"rand" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randc" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randcase" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randomize" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"struct" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"super" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"tagged" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
"this" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||
@ -496,11 +496,11 @@ word [a-zA-Z0-9_]+
|
||||
"const" { FL; return yCONST__LEX; }
|
||||
"cover" { FL; return yCOVER; }
|
||||
"property" { FL; return yPROPERTY; }
|
||||
"union" { FL; return yUNION; }
|
||||
/* Generic unsupported warnings */
|
||||
"assume" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"before" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"sequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"union" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
"within" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
AstVar* m_varAttrp; // Current variable for attribute adding
|
||||
AstCase* m_caseAttrp; // Current case statement for attribute adding
|
||||
AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration
|
||||
AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration
|
||||
int m_pinNum; // Pin number currently parsing
|
||||
string m_instModule; // Name of module referenced for instantiations
|
||||
AstPin* m_instParamp; // Parameters for instantiations
|
||||
@ -70,6 +71,7 @@ public:
|
||||
m_varDecl = AstVarType::UNKNOWN;
|
||||
m_varIO = AstVarType::UNKNOWN;
|
||||
m_varDTypep = NULL;
|
||||
m_memDTypep = NULL;
|
||||
m_pinNum = -1;
|
||||
m_instModule = "";
|
||||
m_instParamp = NULL;
|
||||
@ -345,6 +347,7 @@ class AstSenTree;
|
||||
%token<fl> yOR "or"
|
||||
%token<fl> yOUTPUT "output"
|
||||
%token<fl> yPACKAGE "package"
|
||||
%token<fl> yPACKED "packed"
|
||||
%token<fl> yPARAMETER "parameter"
|
||||
%token<fl> yPMOS "pmos"
|
||||
%token<fl> yPOSEDGE "posedge"
|
||||
@ -355,6 +358,8 @@ class AstSenTree;
|
||||
%token<fl> yPULLDOWN "pulldown"
|
||||
%token<fl> yPULLUP "pullup"
|
||||
%token<fl> yPURE "pure"
|
||||
%token<fl> yRAND "rand"
|
||||
%token<fl> yRANDC "randc"
|
||||
%token<fl> yRCMOS "rcmos"
|
||||
%token<fl> yREAL "real"
|
||||
%token<fl> yREALTIME "realtime"
|
||||
@ -373,6 +378,7 @@ class AstSenTree;
|
||||
%token<fl> ySPECPARAM "specparam"
|
||||
%token<fl> ySTATIC "static"
|
||||
%token<fl> ySTRING "string"
|
||||
%token<fl> ySTRUCT "struct"
|
||||
%token<fl> ySUPPLY0 "supply0"
|
||||
%token<fl> ySUPPLY1 "supply1"
|
||||
%token<fl> yTABLE "table"
|
||||
@ -388,6 +394,7 @@ class AstSenTree;
|
||||
%token<fl> yTRI1 "tri1"
|
||||
%token<fl> yTRUE "true"
|
||||
%token<fl> yTYPEDEF "typedef"
|
||||
%token<fl> yUNION "union"
|
||||
%token<fl> yUNIQUE "unique"
|
||||
%token<fl> yUNIQUE0 "unique0"
|
||||
%token<fl> yUNSIGNED "unsigned"
|
||||
@ -1170,10 +1177,8 @@ data_typeBasic<dtypep>: // IEEE: part of data_type
|
||||
|
||||
data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc references
|
||||
data_typeBasic { $$ = $1; }
|
||||
//UNSUP ySTRUCT packedSigningE '{' struct_union_memberList '}' packed_dimensionListE
|
||||
//UNSUP { UNSUP }
|
||||
//UNSUP yUNION taggedE packedSigningE '{' struct_union_memberList '}' packed_dimensionListE
|
||||
//UNSUP { UNSUP }
|
||||
| struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
|
||||
GRAMMARP->m_modp,VFlagChildDType(),$1),$2,false); }
|
||||
| enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
|
||||
GRAMMARP->m_modp,VFlagChildDType(),$1); }
|
||||
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
|
||||
@ -1187,6 +1192,57 @@ data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc referenc
|
||||
// // IEEE: ps_covergroup: see data_type above
|
||||
;
|
||||
|
||||
data_type_or_void<dtypep>: // ==IEEE: data_type_or_void
|
||||
data_type { $$=$1; }
|
||||
//UNSUP yVOID { UNSUP } // No yTAGGED structures
|
||||
;
|
||||
|
||||
struct_unionDecl<classp>: // IEEE: part of data_type
|
||||
// // packedSigningE is NOP for unpacked
|
||||
ySTRUCT packedSigningE '{' { $<classp>$ = new AstStructDType($1, $2); SYMP->pushNew($<classp>$); }
|
||||
/*cont*/ struct_union_memberList '}'
|
||||
{ $$=$<classp>4; $$->addMembersp($5); SYMP->popScope($$); }
|
||||
| yUNION taggedE packedSigningE '{' { $<classp>$ = new AstUnionDType($1, $3); SYMP->pushNew($<classp>$); }
|
||||
/*cont*/ struct_union_memberList '}'
|
||||
{ $$=$<classp>5; $$->addMembersp($6); SYMP->popScope($$); }
|
||||
;
|
||||
|
||||
struct_union_memberList<nodep>: // IEEE: { struct_union_member }
|
||||
struct_union_member { $$ = $1; }
|
||||
| struct_union_memberList struct_union_member { $$ = $1->addNextNull($2); }
|
||||
;
|
||||
|
||||
struct_union_member<nodep>: // ==IEEE: struct_union_member
|
||||
random_qualifierE data_type_or_void
|
||||
{ GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member.
|
||||
/*cont*/ list_of_member_decl_assignments ';' { $$ = $4; GRAMMARP->m_memDTypep = NULL; }
|
||||
;
|
||||
|
||||
list_of_member_decl_assignments<nodep>: // Derived from IEEE: list_of_variable_decl_assignments
|
||||
member_decl_assignment { $$ = $1; }
|
||||
| list_of_member_decl_assignments ',' member_decl_assignment { $$ = $1->addNextNull($3); }
|
||||
;
|
||||
|
||||
member_decl_assignment<memberp>: // Derived from IEEE: variable_decl_assignment
|
||||
// // At present we allow only packed structures/unions. So this is different from variable_decl_assignment
|
||||
id variable_dimensionListE
|
||||
{ if ($2) $2->v3error("Unsupported: Unpacked array in packed struct/union");
|
||||
$$ = new AstMemberDType($<fl>1, *$1, VFlagChildDType(), GRAMMARP->m_memDTypep->cloneTree(true)); }
|
||||
| id variable_dimensionListE '=' variable_declExpr
|
||||
{ $4->v3error("Unsupported: Initial values in struct/union members."); }
|
||||
| idSVKwd { $$ = NULL; }
|
||||
//
|
||||
// // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]"
|
||||
// // Matches above with variable_dimensionE = "[]"
|
||||
// // IEEE: "class_variable_identifier [ '=' class_new ]"
|
||||
// // variable_dimensionE must be empty
|
||||
// // Pushed into variable_declExpr:dynamic_array_new
|
||||
//
|
||||
// // IEEE: "[ covergroup_variable_identifier ] '=' class_new
|
||||
// // Pushed into variable_declExpr:class_new
|
||||
//UNSUP '=' class_new { UNSUP }
|
||||
;
|
||||
|
||||
list_of_variable_decl_assignments<nodep>: // ==IEEE: list_of_variable_decl_assignments
|
||||
variable_decl_assignment { $$ = $1; }
|
||||
| list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = $1->addNextNull($3); }
|
||||
@ -1254,6 +1310,27 @@ variable_dimension<rangep>: // ==IEEE: variable_dimension
|
||||
// // '[' '$' ':' expr ']' -- anyrange:expr:$
|
||||
;
|
||||
|
||||
random_qualifierE: // IEEE: random_qualifier + empty
|
||||
/*empty*/ { }
|
||||
| random_qualifier { }
|
||||
;
|
||||
|
||||
random_qualifier: // ==IEEE: random_qualifier
|
||||
yRAND { } // Ignored until we support randomize()
|
||||
| yRANDC { } // Ignored until we support randomize()
|
||||
;
|
||||
|
||||
taggedE:
|
||||
/*empty*/ { }
|
||||
//UNSUP yTAGGED { UNSUP }
|
||||
;
|
||||
|
||||
packedSigningE<signstate>:
|
||||
// // AstNumeric::NOSIGN overloaded to indicate not packed
|
||||
/*empty*/ { $$ = signedst_NOSIGN; }
|
||||
| yPACKED signingE { $$ = $2; if ($$ == signedst_NOSIGN) $$ = signedst_UNSIGNED; }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
// enum
|
||||
|
||||
@ -1353,8 +1430,8 @@ type_declaration<nodep>: // ==IEEE: type_declaration
|
||||
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
|
||||
| yTYPEDEF id ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$2); SYMP->reinsert($$); }
|
||||
| yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
//UNSUP yTYPEDEF ySTRUCT idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
//UNSUP yTYPEDEF yUNION idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
| yTYPEDEF ySTRUCT idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
| yTYPEDEF yUNION idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
//UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
|
||||
;
|
||||
|
||||
|
@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug181");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
|
18
test_regress/t/t_struct_notfound_bad.pl
Executable file
18
test_regress/t/t_struct_notfound_bad.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_struct_notfound_bad.v:\d+: Member \'nfmember\' not found in structure
|
||||
%Error: Exiting due to.*',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
15
test_regress/t/t_struct_notfound_bad.v
Normal file
15
test_regress/t/t_struct_notfound_bad.v
Normal file
@ -0,0 +1,15 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2012 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
typedef struct packed { bit m; } struct_t;
|
||||
struct_t s;
|
||||
|
||||
initial begin
|
||||
s.nfmember = 0; // Member not found
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug181");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
|
@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug181");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
|
@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug181");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
|
18
test_regress/t/t_struct_unpacked_bad.pl
Executable file
18
test_regress/t/t_struct_unpacked_bad.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
q{%Error: t/t_struct_unpacked_bad.v:8: Unsupported: Unpacked struct/union
|
||||
.*%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
16
test_regress/t/t_struct_unpacked_bad.v
Normal file
16
test_regress/t/t_struct_unpacked_bad.v
Normal file
@ -0,0 +1,16 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Wilson Snyder.
|
||||
|
||||
module x;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} notpacked_t;
|
||||
|
||||
typedef struct packed {
|
||||
notpacked_t a;
|
||||
} ispacked_t;
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user