Support parameter arrays, bug683.
This commit is contained in:
parent
091818483a
commit
28e35a64ea
2
Changes
2
Changes
|
|
@ -15,6 +15,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
*** Add PINCONNECTEMPTY warning. [Holger Waechtler]
|
*** Add PINCONNECTEMPTY warning. [Holger Waechtler]
|
||||||
|
|
||||||
|
*** Support parameter arrays, bug683. [Jeremy Bennett]
|
||||||
|
|
||||||
**** Documentation fixes, bug723. [Glen Gibb]
|
**** Documentation fixes, bug723. [Glen Gibb]
|
||||||
|
|
||||||
**** Fix tracing of package variables and real arrays.
|
**** Fix tracing of package variables and real arrays.
|
||||||
|
|
|
||||||
|
|
@ -977,7 +977,6 @@ public:
|
||||||
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst
|
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst
|
||||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||||
AstNode* attrsp() const { return op4p()->castNode(); } // op4 = Attributes during early parse
|
AstNode* attrsp() const { return op4p()->castNode(); } // op4 = Attributes during early parse
|
||||||
bool hasSimpleInit() const { return (op3p() && !op3p()->castInitArray()); }
|
|
||||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||||
void attrClockEn(bool flag) { m_attrClockEn = flag; }
|
void attrClockEn(bool flag) { m_attrClockEn = flag; }
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ private:
|
||||||
bool m_doV; // Verilog, not C++ conversion
|
bool m_doV; // Verilog, not C++ conversion
|
||||||
bool m_doGenerate; // Postpone width checking inside generate
|
bool m_doGenerate; // Postpone width checking inside generate
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
|
AstArraySel* m_selp; // Current select
|
||||||
AstNode* m_scopep; // Current scope
|
AstNode* m_scopep; // Current scope
|
||||||
AstAttrOf* m_attrp; // Current attribute
|
AstAttrOf* m_attrp; // Current attribute
|
||||||
|
|
||||||
|
|
@ -1221,15 +1222,35 @@ private:
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_attrp = oldAttr;
|
m_attrp = oldAttr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||||
|
nodep->bitp()->iterateAndNext(*this);
|
||||||
|
if (nodep->bitp()->castConst()
|
||||||
|
&& nodep->fromp()->castVarRef()
|
||||||
|
// Need to make sure it's an array object so don't mis-allow a constant (bug509.)
|
||||||
|
&& nodep->fromp()->castVarRef()->varp()
|
||||||
|
&& nodep->fromp()->castVarRef()->varp()->valuep()->castInitArray()) {
|
||||||
|
m_selp = nodep; // Ask visit(AstVarRef) to replace varref with const
|
||||||
|
}
|
||||||
|
nodep->fromp()->iterateAndNext(*this);
|
||||||
|
if (nodep->fromp()->castConst()) { // It did.
|
||||||
|
if (!m_selp) {
|
||||||
|
nodep->v3error("Illegal assignment of constant to unpacked array");
|
||||||
|
} else {
|
||||||
|
nodep->replaceWith(nodep->fromp()->unlinkFrBack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_selp = NULL;
|
||||||
|
}
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||||
bool did=false;
|
bool did=false;
|
||||||
if (m_doV && nodep->varp()->hasSimpleInit() && !m_attrp) {
|
if (m_doV && nodep->varp()->valuep() && !m_attrp) {
|
||||||
//if (debug()) nodep->varp()->valuep()->dumpTree(cout," visitvaref: ");
|
//if (debug()) valuep->dumpTree(cout," visitvaref: ");
|
||||||
nodep->varp()->valuep()->iterateAndNext(*this);
|
nodep->varp()->valuep()->iterateAndNext(*this); // May change nodep->varp()->valuep()
|
||||||
if (operandConst(nodep->varp()->valuep())
|
AstNode* valuep = nodep->varp()->valuep();
|
||||||
&& !nodep->lvalue()
|
if (!nodep->lvalue()
|
||||||
&& ((!m_params // Can reduce constant wires into equations
|
&& ((!m_params // Can reduce constant wires into equations
|
||||||
&& m_doNConst
|
&& m_doNConst
|
||||||
&& v3Global.opt.oConst()
|
&& v3Global.opt.oConst()
|
||||||
|
|
@ -1237,12 +1258,24 @@ private:
|
||||||
&& nodep->varp()->isInput())
|
&& nodep->varp()->isInput())
|
||||||
&& !nodep->varp()->isSigPublic())
|
&& !nodep->varp()->isSigPublic())
|
||||||
|| nodep->varp()->isParam())) {
|
|| nodep->varp()->isParam())) {
|
||||||
AstConst* constp = nodep->varp()->valuep()->castConst();
|
if (operandConst(valuep)) {
|
||||||
const V3Number& num = constp->num();
|
const V3Number& num = valuep->castConst()->num();
|
||||||
//UINFO(2,"constVisit "<<(void*)constp<<" "<<num<<endl);
|
//UINFO(2,"constVisit "<<(void*)valuep<<" "<<num<<endl);
|
||||||
replaceNum(nodep, num); nodep=NULL;
|
replaceNum(nodep, num); nodep=NULL;
|
||||||
did=true;
|
did=true;
|
||||||
}
|
}
|
||||||
|
else if (m_selp && valuep->castInitArray()) {
|
||||||
|
int bit = m_selp->bitConst();
|
||||||
|
AstNode* itemp = valuep->castInitArray()->initsp();
|
||||||
|
for (int n=0; n<bit && itemp; ++n, itemp=itemp->nextp()) {}
|
||||||
|
if (itemp->castConst()) {
|
||||||
|
const V3Number& num = itemp->castConst()->num();
|
||||||
|
//UINFO(2,"constVisit "<<(void*)valuep<<" "<<num<<endl);
|
||||||
|
replaceNum(nodep, num); nodep=NULL;
|
||||||
|
did=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!did && m_required) {
|
if (!did && m_required) {
|
||||||
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->varp()->prettyName());
|
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->varp()->prettyName());
|
||||||
|
|
@ -1666,6 +1699,10 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstInitArray* nodep, AstNUser*) {
|
||||||
|
// Constant if all children are constant
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
|
||||||
// These are converted by V3Param. Don't constify as we don't want the from() VARREF to disappear, if any
|
// These are converted by V3Param. Don't constify as we don't want the from() VARREF to disappear, if any
|
||||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||||
|
|
@ -1711,6 +1748,12 @@ private:
|
||||||
|
|
||||||
//-----
|
//-----
|
||||||
// Below lines are magic expressions processed by astgen
|
// Below lines are magic expressions processed by astgen
|
||||||
|
// TREE_SKIP_VISIT("AstNODETYPE") # Rename normal visit to visitGen and don't iterate
|
||||||
|
//-----
|
||||||
|
|
||||||
|
TREE_SKIP_VISIT("ArraySel");
|
||||||
|
|
||||||
|
//-----
|
||||||
// "AstNODETYPE { # bracket not paren
|
// "AstNODETYPE { # bracket not paren
|
||||||
// $accessor_name, ...
|
// $accessor_name, ...
|
||||||
// # ,, gets replaced with a , rather than &&
|
// # ,, gets replaced with a , rather than &&
|
||||||
|
|
@ -2038,6 +2081,7 @@ public:
|
||||||
m_warn = false;
|
m_warn = false;
|
||||||
m_wremove = true; // Overridden in visitors
|
m_wremove = true; // Overridden in visitors
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
|
m_selp = NULL;
|
||||||
m_scopep = NULL;
|
m_scopep = NULL;
|
||||||
m_attrp = NULL;
|
m_attrp = NULL;
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ public:
|
||||||
string vfmt, char fmtLetter);
|
string vfmt, char fmtLetter);
|
||||||
|
|
||||||
void emitVarDecl(AstVar* nodep, const string& prefixIfImp);
|
void emitVarDecl(AstVar* nodep, const string& prefixIfImp);
|
||||||
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_STATIC, EVL_ALL} EisWhich;
|
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_PAR, EVL_ALL} EisWhich;
|
||||||
void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp);
|
void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp);
|
||||||
void emitVarCtors();
|
void emitVarCtors();
|
||||||
bool emitSimpleOk(AstNodeMath* nodep);
|
bool emitSimpleOk(AstNodeMath* nodep);
|
||||||
|
|
@ -1309,7 +1309,9 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
|
||||||
// Constructor deals with it
|
// Constructor deals with it
|
||||||
}
|
}
|
||||||
else if (varp->isParam()) {
|
else if (varp->isParam()) {
|
||||||
if (!varp->hasSimpleInit()) nodep->v3fatalSrc("No init for a param?");
|
if (!varp->valuep()) nodep->v3fatalSrc("No init for a param?");
|
||||||
|
// If a simple CONST value we initialize it using an enum
|
||||||
|
// If an ARRAYINIT we initialize it using an initial block similar to a signal
|
||||||
//puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n");
|
//puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n");
|
||||||
}
|
}
|
||||||
else if (AstInitArray* initarp = varp->valuep()->castInitArray()) {
|
else if (AstInitArray* initarp = varp->valuep()->castInitArray()) {
|
||||||
|
|
@ -1673,6 +1675,7 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
|
||||||
case EVL_IO: doit = varp->isIO(); break;
|
case EVL_IO: doit = varp->isIO(); break;
|
||||||
case EVL_SIG: doit = (varp->isSignal() && !varp->isIO()); break;
|
case EVL_SIG: doit = (varp->isSignal() && !varp->isIO()); break;
|
||||||
case EVL_TEMP: doit = (varp->isTemp() && !varp->isIO()); break;
|
case EVL_TEMP: doit = (varp->isTemp() && !varp->isIO()); break;
|
||||||
|
case EVL_PAR: doit = (varp->isParam() && !varp->valuep()->castConst()); break;
|
||||||
default: v3fatalSrc("Bad Case");
|
default: v3fatalSrc("Bad Case");
|
||||||
}
|
}
|
||||||
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
|
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
|
||||||
|
|
@ -1828,6 +1831,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||||
puts("\n// PARAMETERS\n");
|
puts("\n// PARAMETERS\n");
|
||||||
if (modp->isTop()) puts("// Parameters marked /*verilator public*/ for use by application code\n");
|
if (modp->isTop()) puts("// Parameters marked /*verilator public*/ for use by application code\n");
|
||||||
ofp()->putsPrivate(false); // public:
|
ofp()->putsPrivate(false); // public:
|
||||||
|
emitVarList(modp->stmtsp(), EVL_PAR, ""); // Only those that are non-CONST
|
||||||
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||||
if (AstVar* varp = nodep->castVar()) {
|
if (AstVar* varp = nodep->castVar()) {
|
||||||
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
|
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
|
||||||
|
|
@ -1837,7 +1841,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||||
if (varp->isWide()) { // Unsupported for output
|
if (varp->isWide()) { // Unsupported for output
|
||||||
puts("// enum WData "+varp->name()+" //wide");
|
puts("// enum WData "+varp->name()+" //wide");
|
||||||
} else if (!varp->valuep()->castConst()) { // Unsupported for output
|
} else if (!varp->valuep()->castConst()) { // Unsupported for output
|
||||||
puts("// enum IData "+varp->name()+" //not simple value");
|
//puts("// enum ..... "+varp->name()+" //not simple value, see variable above instead");
|
||||||
} else {
|
} else {
|
||||||
puts("enum ");
|
puts("enum ");
|
||||||
puts(varp->isQuad()?"_QData":"_IData");
|
puts(varp->isQuad()?"_QData":"_IData");
|
||||||
|
|
|
||||||
|
|
@ -230,8 +230,16 @@ private:
|
||||||
if (!nodep->user5SetOnce()) { // Process once
|
if (!nodep->user5SetOnce()) { // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->isParam()) {
|
if (nodep->isParam()) {
|
||||||
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
if (!nodep->valuep()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
||||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||||
|
if (!nodep->valuep()->castConst()) { // Complex init, like an array
|
||||||
|
// Make a new INITIAL to set the value.
|
||||||
|
// This allows the normal array/struct handling code to properly initialize the parameter
|
||||||
|
nodep->addNext(new AstInitial(nodep->fileline(),
|
||||||
|
new AstAssign(nodep->fileline(),
|
||||||
|
new AstVarRef(nodep->fileline(), nodep, true),
|
||||||
|
nodep->valuep()->cloneTree(true))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1277,6 +1277,13 @@ private:
|
||||||
patp->accept(*this,WidthVP(memp,BOTH).p());
|
patp->accept(*this,WidthVP(memp,BOTH).p());
|
||||||
// Convert to concat for now
|
// Convert to concat for now
|
||||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||||
|
if (valuep->castConst()) {
|
||||||
|
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
|
||||||
|
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
|
||||||
|
pushDeletep(valuep); valuep=NULL;
|
||||||
|
valuep = newp;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!newp) newp = valuep;
|
if (!newp) newp = valuep;
|
||||||
else {
|
else {
|
||||||
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
|
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
|
||||||
|
|
@ -1340,6 +1347,13 @@ private:
|
||||||
patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p());
|
patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p());
|
||||||
// Convert to InitArray or constify immediately
|
// Convert to InitArray or constify immediately
|
||||||
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
AstNode* valuep = patp->lhssp()->unlinkFrBack();
|
||||||
|
if (valuep->castConst()) {
|
||||||
|
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
|
||||||
|
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
|
||||||
|
pushDeletep(valuep); valuep=NULL;
|
||||||
|
valuep = newp;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (arrayp->castUnpackArrayDType()) {
|
if (arrayp->castUnpackArrayDType()) {
|
||||||
if (!newp) {
|
if (!newp) {
|
||||||
newp = new AstInitArray(nodep->fileline(), arrayp, valuep);
|
newp = new AstInitArray(nodep->fileline(), arrayp, valuep);
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,22 @@ class WidthCommitVisitor : public AstNVisitor {
|
||||||
// AstVar::user1p -> bool, processed
|
// AstVar::user1p -> bool, processed
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// METHODS
|
||||||
|
static AstConst* newIfConstCommitSize (AstConst* nodep) {
|
||||||
|
if ((nodep->dtypep()->width() != nodep->num().width())
|
||||||
|
|| !nodep->num().sized()) { // Need to force the number rrom unsized to sized
|
||||||
|
V3Number num (nodep->fileline(), nodep->dtypep()->width());
|
||||||
|
num.opAssign(nodep->num());
|
||||||
|
num.isSigned(nodep->isSigned());
|
||||||
|
AstConst* newp = new AstConst(nodep->fileline(), num);
|
||||||
|
newp->dtypeFrom(nodep);
|
||||||
|
return newp;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// METHODS
|
// METHODS
|
||||||
void editDType(AstNode* nodep) {
|
void editDType(AstNode* nodep) {
|
||||||
|
|
@ -97,13 +113,7 @@ private:
|
||||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||||
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype");
|
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype");
|
||||||
nodep->dtypep()->accept(*this); // Do datatype first
|
nodep->dtypep()->accept(*this); // Do datatype first
|
||||||
if ((nodep->dtypep()->width() != nodep->num().width())
|
if (AstConst* newp = newIfConstCommitSize(nodep)) {
|
||||||
|| !nodep->num().sized()) { // Need to force the number rrom unsized to sized
|
|
||||||
V3Number num (nodep->fileline(), nodep->dtypep()->width());
|
|
||||||
num.opAssign(nodep->num());
|
|
||||||
num.isSigned(nodep->isSigned());
|
|
||||||
AstConst* newp = new AstConst(nodep->fileline(), num);
|
|
||||||
newp->dtypeFrom(nodep);
|
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
AstNode* oldp = nodep; nodep = newp;
|
AstNode* oldp = nodep; nodep = newp;
|
||||||
//if (debug()>4) oldp->dumpTree(cout," fixConstSize_old: ");
|
//if (debug()>4) oldp->dumpTree(cout," fixConstSize_old: ");
|
||||||
|
|
|
||||||
12
src/astgen
12
src/astgen
|
|
@ -424,6 +424,11 @@ sub tree_line {
|
||||||
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
|
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
|
||||||
push @{$self->{treeop}{$type}}, $typefunc;
|
push @{$self->{treeop}{$type}}, $typefunc;
|
||||||
}
|
}
|
||||||
|
elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) {
|
||||||
|
my $type = $1;
|
||||||
|
$self->{tree_skip_visit}{$type} = 1;
|
||||||
|
$::Classes{$type} or $self->error("Unknown node type: $type");
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
$self->error("Unknown astgen op: $func");
|
$self->error("Unknown astgen op: $func");
|
||||||
}
|
}
|
||||||
|
|
@ -598,9 +603,12 @@ sub tree_base {
|
||||||
@out_for_type,
|
@out_for_type,
|
||||||
" }\n") if ($out_for_type[0]);
|
" }\n") if ($out_for_type[0]);
|
||||||
} elsif ($out_for_type[0]) { # Other types with something to print
|
} elsif ($out_for_type[0]) { # Other types with something to print
|
||||||
|
my $skip = $self->{tree_skip_visit}{$type};
|
||||||
|
my $gen = $skip ? "Gen" : "";
|
||||||
$self->print(" // Generated by astgen\n",
|
$self->print(" // Generated by astgen\n",
|
||||||
" virtual void visit(Ast${type}* nodep, AstNUser*) {\n",
|
" virtual void visit$gen(Ast${type}* nodep, AstNUser*) {\n",
|
||||||
" nodep->iterateChildren(*this);\n",
|
($skip?"":
|
||||||
|
" nodep->iterateChildren(*this);\n"),
|
||||||
@out_for_type,
|
@out_for_type,
|
||||||
" }\n");
|
" }\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1892,10 +1892,6 @@ netId<strp>:
|
||||||
| idSVKwd { $$ = $1; $<fl>$=$<fl>1; }
|
| idSVKwd { $$ = $1; $<fl>$=$<fl>1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
sigId<varp>:
|
|
||||||
id { $$ = VARDONEA($<fl>1,*$1, NULL, NULL); }
|
|
||||||
;
|
|
||||||
|
|
||||||
sigAttrListE<nodep>:
|
sigAttrListE<nodep>:
|
||||||
/* empty */ { $$ = NULL; }
|
/* empty */ { $$ = NULL; }
|
||||||
| sigAttrList { $$ = $1; }
|
| sigAttrList { $$ = $1; }
|
||||||
|
|
@ -1958,7 +1954,8 @@ packed_dimension<rangep>: // ==IEEE: packed_dimension
|
||||||
param_assignment<varp>: // ==IEEE: param_assignment
|
param_assignment<varp>: // ==IEEE: param_assignment
|
||||||
// // IEEE: constant_param_expression
|
// // IEEE: constant_param_expression
|
||||||
// // constant_param_expression: '$' is in expr
|
// // constant_param_expression: '$' is in expr
|
||||||
sigId sigAttrListE '=' expr { $$ = $1; $1->addAttrsp($2); $$->valuep($4); }
|
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' expr
|
||||||
|
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
|
||||||
//UNSUP: exprOrDataType instead of expr
|
//UNSUP: exprOrDataType instead of expr
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2013 by Jeremy Bennett.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
typedef enum int {
|
||||||
|
PADTYPE_DEFAULT = 32'd0,
|
||||||
|
PADTYPE_GPIO,
|
||||||
|
PADTYPE_VDD,
|
||||||
|
PADTYPE_GND
|
||||||
|
} t_padtype;
|
||||||
|
|
||||||
|
localparam int STR_PINID [0:15]
|
||||||
|
= '{
|
||||||
|
"DEF", "ERR", "ERR", "ERR", "ERR", "ERR", "ERR", "ERR",
|
||||||
|
"PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7"
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
t_padtype padtype;
|
||||||
|
int aux;
|
||||||
|
} t_pin_descriptor;
|
||||||
|
|
||||||
|
localparam t_pin_descriptor
|
||||||
|
PINOUT[ 1: 6]
|
||||||
|
= '{
|
||||||
|
'{default:0, padtype:PADTYPE_GPIO, aux:1},
|
||||||
|
'{default:0, padtype:PADTYPE_GPIO},
|
||||||
|
'{default:0, padtype:PADTYPE_GPIO},
|
||||||
|
'{default:0, padtype:PADTYPE_GPIO},
|
||||||
|
'{default:0, padtype:PADTYPE_VDD},
|
||||||
|
'{default:0, padtype:PADTYPE_GND}
|
||||||
|
};
|
||||||
|
|
||||||
|
localparam int PINOUT_SIZE = 6;
|
||||||
|
localparam int PINOUT_WA[1:PINOUT_SIZE][3]
|
||||||
|
= '{
|
||||||
|
'{0, PADTYPE_GPIO, 0},
|
||||||
|
'{1, PADTYPE_GPIO, 0},
|
||||||
|
'{2, PADTYPE_GPIO, 0},
|
||||||
|
'{5, PADTYPE_GPIO, 0},
|
||||||
|
'{6, PADTYPE_VDD, 0},
|
||||||
|
'{8, PADTYPE_GND , 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
const int pinout_static_const[1:PINOUT_SIZE][3]
|
||||||
|
= '{
|
||||||
|
'{0, PADTYPE_GPIO, 0},
|
||||||
|
'{1, PADTYPE_GPIO, 0},
|
||||||
|
'{2, PADTYPE_GPIO, 0},
|
||||||
|
'{5, PADTYPE_GPIO, 0},
|
||||||
|
'{6, PADTYPE_VDD, 0},
|
||||||
|
'{8, PADTYPE_GND , 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure consants propagate
|
||||||
|
checkstr #(.PINID(STR_PINID[1]),
|
||||||
|
.EXP("ERR"))
|
||||||
|
substr1 ();
|
||||||
|
checkstr #(.PINID(STR_PINID[8]),
|
||||||
|
.EXP("PA0"))
|
||||||
|
substr8 ();
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$display("PINID1 %s", STR_PINID[1]);
|
||||||
|
$display("PINID8 %s", STR_PINID[8]);
|
||||||
|
if (STR_PINID[1] != "ERR") $stop;
|
||||||
|
if (STR_PINID[8] != "PA0") $stop;
|
||||||
|
if (pinout_static_const[0][0] != 0) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module checkstr;
|
||||||
|
parameter int PINID = " ";
|
||||||
|
parameter int EXP = " ";
|
||||||
|
initial begin
|
||||||
|
$display("PID %s EXP %s", PINID, EXP);
|
||||||
|
if (EXP != "ERR" && EXP != "PA0") $stop;
|
||||||
|
if (PINID != EXP) $stop;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue