forked from github/verilator
Delay parsing of associative arrays until dtypes known.
This commit is contained in:
parent
46e10173f8
commit
d42f9c095b
@ -231,33 +231,23 @@ public:
|
|||||||
virtual bool same(const AstNode* samep) const { return true; }
|
virtual bool same(const AstNode* samep) const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstAssocRange : public AstNodeRange {
|
class AstBracketRange : public AstNodeRange {
|
||||||
// Associative array range specification
|
// Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range,
|
||||||
// Only for early parsing - becomes AstAssocDType
|
// unknown until lhsp type is determined
|
||||||
public:
|
public:
|
||||||
AstAssocRange(FileLine* fl, AstNodeDType* dtp)
|
AstBracketRange(FileLine* fl, AstNode* elementsp)
|
||||||
: ASTGEN_SUPER(fl) {
|
: ASTGEN_SUPER(fl) {
|
||||||
setOp1p(dtp);
|
setOp1p(elementsp);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(AssocRange)
|
ASTNODE_NODE_FUNCS(BracketRange)
|
||||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
|
||||||
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
|
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
|
||||||
virtual bool same(const AstNode* samep) const { return true; }
|
|
||||||
AstNodeDType* keyDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class AstQueueRange : public AstNodeRange {
|
|
||||||
// Queue range specification
|
|
||||||
// Only for early parsing - becomes AstQueueDType
|
|
||||||
public:
|
|
||||||
explicit AstQueueRange(FileLine* fl)
|
|
||||||
: ASTGEN_SUPER(fl) {}
|
|
||||||
ASTNODE_NODE_FUNCS(QueueRange)
|
|
||||||
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
virtual string emitC() { V3ERROR_NA_RETURN(""); }
|
||||||
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
|
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
virtual bool same(const AstNode* samep) const { return true; }
|
virtual bool same(const AstNode* samep) const { return true; }
|
||||||
|
// Will be removed in V3Width, which relies on this
|
||||||
|
// being a child not a dtype pointed node
|
||||||
|
virtual bool maybePointedTo() const { return false; }
|
||||||
|
AstNode* elementsp() const { return op1p(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstUnsizedRange : public AstNodeRange {
|
class AstUnsizedRange : public AstNodeRange {
|
||||||
@ -568,6 +558,36 @@ public:
|
|||||||
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AstBracketArrayDType : public AstNodeDType {
|
||||||
|
// Associative/Queue/Normal array data type, ie "[dtype_or_expr]"
|
||||||
|
// only for early parsing then becomes another data type
|
||||||
|
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||||
|
// Children: DTYPE (the key)
|
||||||
|
public:
|
||||||
|
AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp)
|
||||||
|
: ASTGEN_SUPER(fl) {
|
||||||
|
setOp1p(dtp); // Only for parser
|
||||||
|
setOp2p(elementsp); // Only for parser
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(BracketArrayDType)
|
||||||
|
virtual bool similarDType(AstNodeDType* samep) const { V3ERROR_NA_RETURN(false); }
|
||||||
|
// op1 = Range of variable
|
||||||
|
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
|
||||||
|
virtual AstNodeDType* subDTypep() const { return childDTypep(); }
|
||||||
|
// op2 = Range of variable
|
||||||
|
AstNode* elementsp() const { return op2p(); }
|
||||||
|
// METHODS
|
||||||
|
// Will be removed in V3Width, which relies on this
|
||||||
|
// being a child not a dtype pointed node
|
||||||
|
virtual bool maybePointedTo() const { return false; }
|
||||||
|
virtual AstBasicDType* basicp() const { return NULL; }
|
||||||
|
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||||
|
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
|
||||||
|
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||||
|
virtual int widthAlignBytes() const { V3ERROR_NA_RETURN(0); }
|
||||||
|
virtual int widthTotalBytes() const { V3ERROR_NA_RETURN(0); }
|
||||||
|
};
|
||||||
|
|
||||||
class AstDynArrayDType : public AstNodeDType {
|
class AstDynArrayDType : public AstNodeDType {
|
||||||
// Dynamic array data type, ie "[]"
|
// Dynamic array data type, ie "[]"
|
||||||
// Children: DTYPE (moved to refDTypep() in V3Width)
|
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||||
|
@ -181,6 +181,12 @@ private:
|
|||||||
if (AstUnpackArrayDType* adtypep = VN_CAST(nodep, UnpackArrayDType)) {
|
if (AstUnpackArrayDType* adtypep = VN_CAST(nodep, UnpackArrayDType)) {
|
||||||
return adtypep->subDTypep();
|
return adtypep->subDTypep();
|
||||||
}
|
}
|
||||||
|
// We have not resolved parameter of the child yet, so still
|
||||||
|
// have BracketArrayDType's. We'll presume it'll end up as assignment
|
||||||
|
// compatible (or V3Width will complain).
|
||||||
|
if (AstBracketArrayDType* adtypep = VN_CAST(nodep, BracketArrayDType)) {
|
||||||
|
return adtypep->subDTypep();
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
|
void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
|
||||||
|
@ -120,8 +120,6 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
|
|||||||
if (rangep && isPacked) {
|
if (rangep && isPacked) {
|
||||||
arrayp
|
arrayp
|
||||||
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
||||||
} else if (VN_IS(nrangep, QueueRange)) {
|
|
||||||
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
|
|
||||||
} else if (rangep
|
} else if (rangep
|
||||||
&& (VN_IS(rangep->leftp(), Unbounded)
|
&& (VN_IS(rangep->leftp(), Unbounded)
|
||||||
|| VN_IS(rangep->rightp(), Unbounded))) {
|
|| VN_IS(rangep->rightp(), Unbounded))) {
|
||||||
@ -132,12 +130,11 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
|
|||||||
rangep);
|
rangep);
|
||||||
} else if (VN_IS(nrangep, UnsizedRange)) {
|
} else if (VN_IS(nrangep, UnsizedRange)) {
|
||||||
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
|
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
|
||||||
} else if (VN_IS(nrangep, AssocRange)) {
|
} else if (VN_IS(nrangep, BracketRange)) {
|
||||||
AstAssocRange* arangep = VN_CAST(nrangep, AssocRange);
|
AstBracketRange* arangep = VN_CAST(nrangep, BracketRange);
|
||||||
AstNodeDType* keyp = arangep->keyDTypep();
|
AstNode* keyp = arangep->elementsp()->unlinkFrBack();
|
||||||
keyp->unlinkFrBack();
|
arrayp = new AstBracketArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp,
|
||||||
arrayp
|
keyp);
|
||||||
= new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
|
|
||||||
} else {
|
} else {
|
||||||
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
||||||
}
|
}
|
||||||
|
@ -1061,7 +1061,7 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstUnbounded* nodep) VL_OVERRIDE {
|
virtual void visit(AstUnbounded* nodep) VL_OVERRIDE {
|
||||||
nodep->dtypeSetSigned32(); // Used in int context
|
nodep->dtypeSetSigned32(); // Used in int context
|
||||||
if (!VN_IS(nodep->backp(), IsUnbounded)
|
if (!VN_IS(nodep->backp(), IsUnbounded) && !VN_IS(nodep->backp(), BracketArrayDType)
|
||||||
&& !(VN_IS(nodep->backp(), Var) && VN_CAST(nodep->backp(), Var)->isParam())) {
|
&& !(VN_IS(nodep->backp(), Var) && VN_CAST(nodep->backp(), Var)->isParam())) {
|
||||||
nodep->v3error("Unsupported/illegal unbounded ('$') in this context.");
|
nodep->v3error("Unsupported/illegal unbounded ('$') in this context.");
|
||||||
}
|
}
|
||||||
@ -1354,6 +1354,35 @@ private:
|
|||||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||||
UINFO(4, "dtWidthed " << nodep << endl);
|
UINFO(4, "dtWidthed " << nodep << endl);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstBracketArrayDType* nodep) VL_OVERRIDE {
|
||||||
|
// Type inserted only because parser didn't know elementsp() type
|
||||||
|
// Resolve elementsp's type
|
||||||
|
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
|
||||||
|
// We must edit when dtype still under normal nodes and before type table
|
||||||
|
// See notes in iterateEditMoveDTypep
|
||||||
|
AstNodeDType* childp = nodep->childDTypep();
|
||||||
|
childp->unlinkFrBack();
|
||||||
|
AstNode* elementsp = nodep->elementsp()->unlinkFrBack();
|
||||||
|
AstNode* newp;
|
||||||
|
if (VN_IS(elementsp, Unbounded)) {
|
||||||
|
newp = new AstQueueDType(nodep->fileline(), VFlagChildDType(), childp, NULL);
|
||||||
|
VL_DO_DANGLING(elementsp->deleteTree(), elementsp);
|
||||||
|
} else if (AstNodeDType* keyp = VN_CAST(elementsp, NodeDType)) {
|
||||||
|
newp = new AstAssocArrayDType(nodep->fileline(), VFlagChildDType(), childp, keyp);
|
||||||
|
} else {
|
||||||
|
// Must be expression that is constant, but we'll determine that later
|
||||||
|
newp = new AstUnpackArrayDType(
|
||||||
|
nodep->fileline(), VFlagChildDType(), childp,
|
||||||
|
new AstRange(nodep->fileline(), new AstConst(elementsp->fileline(), 0),
|
||||||
|
new AstSub(elementsp->fileline(), elementsp,
|
||||||
|
new AstConst(elementsp->fileline(), 1))));
|
||||||
|
}
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
|
// Normally parent's iteration would cover this, but we might have entered by a specific
|
||||||
|
// visit
|
||||||
|
VL_DO_DANGLING(userIterate(newp, NULL), newp);
|
||||||
|
}
|
||||||
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
|
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
|
||||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||||
@ -1432,6 +1461,10 @@ private:
|
|||||||
}
|
}
|
||||||
userIterateChildren(nodep, NULL);
|
userIterateChildren(nodep, NULL);
|
||||||
if (nodep->subDTypep()) {
|
if (nodep->subDTypep()) {
|
||||||
|
// Normally iterateEditMoveDTypep iterate would work, but the refs are under
|
||||||
|
// the TypeDef which will upset iterateEditMoveDTypep as it can't find it under
|
||||||
|
// this node's childDTypep
|
||||||
|
userIterate(nodep->subDTypep(), NULL);
|
||||||
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
||||||
nodep->typedefp(NULL); // Note until line above subDTypep() may have followed this
|
nodep->typedefp(NULL); // Note until line above subDTypep() may have followed this
|
||||||
// Widths are resolved, but special iterate to check for recurstion
|
// Widths are resolved, but special iterate to check for recurstion
|
||||||
@ -4979,6 +5012,9 @@ private:
|
|||||||
}
|
}
|
||||||
if (!dtnodep->didWidth()) {
|
if (!dtnodep->didWidth()) {
|
||||||
UINFO(9, "iterateEditMoveDTypep pointer iterating " << dtnodep << endl);
|
UINFO(9, "iterateEditMoveDTypep pointer iterating " << dtnodep << endl);
|
||||||
|
// See notes in visit(AstBracketArrayDType*)
|
||||||
|
UASSERT_OBJ(!VN_IS(dtnodep, BracketArrayDType), parentp,
|
||||||
|
"Brackets should have been iterated as children");
|
||||||
userIterate(dtnodep, NULL);
|
userIterate(dtnodep, NULL);
|
||||||
UASSERT_OBJ(dtnodep->didWidth(), parentp,
|
UASSERT_OBJ(dtnodep->didWidth(), parentp,
|
||||||
"iterateEditMoveDTypep didn't get width resolution");
|
"iterateEditMoveDTypep didn't get width resolution");
|
||||||
|
@ -1962,11 +1962,10 @@ variable_dimension<rangep>: // ==IEEE: variable_dimension
|
|||||||
'[' ']' { $$ = new AstUnsizedRange($1); }
|
'[' ']' { $$ = new AstUnsizedRange($1); }
|
||||||
// // IEEE: unpacked_dimension
|
// // IEEE: unpacked_dimension
|
||||||
| anyrange { $$ = $1; }
|
| anyrange { $$ = $1; }
|
||||||
| '[' constExpr ']' { if (VN_IS($2, Unbounded)) { $2->deleteTree(); $$ = new AstQueueRange($1); }
|
// // IEEE: unpacked_dimension (if const_expr)
|
||||||
else { $$ = new AstRange($1, new AstConst($1, 0),
|
// // IEEE: associative_dimension (if data_type)
|
||||||
new AstSub($1, $2, new AstConst($1, 1))); } }
|
// // Can't tell which until see if expr is data type or not
|
||||||
// // IEEE: associative_dimension
|
| '[' exprOrDataType ']' { $$ = new AstBracketRange($1, $2); }
|
||||||
| '[' data_type ']' { $$ = new AstAssocRange($1, $2); }
|
|
||||||
| yP_BRASTAR ']' { $$ = NULL; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); }
|
| yP_BRASTAR ']' { $$ = NULL; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); }
|
||||||
| '[' '*' ']' { $$ = NULL; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); }
|
| '[' '*' ']' { $$ = NULL; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); }
|
||||||
// // IEEE: queue_dimension
|
// // IEEE: queue_dimension
|
||||||
|
@ -1 +1 @@
|
|||||||
source ../src/.gdbinit
|
source ~/SandBox/homecvs/v4/verilator/src/.gdbinit
|
||||||
|
17
test_regress/t/t_param_bracket.pl
Executable file
17
test_regress/t/t_param_bracket.pl
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env 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.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(linter => 1);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
18
test_regress/t/t_param_bracket.v
Normal file
18
test_regress/t/t_param_bracket.v
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2020 by Wilson Snyder;
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t
|
||||||
|
#(parameter WIDTH = 8)
|
||||||
|
(/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
o
|
||||||
|
);
|
||||||
|
output [WIDTH-1:0] o;
|
||||||
|
localparam DEPTH = $clog2(5);
|
||||||
|
// Note single bracket below
|
||||||
|
reg [WIDTH-1:0] arid [1<<DEPTH];
|
||||||
|
assign o = arid[0];
|
||||||
|
endmodule
|
@ -55,7 +55,6 @@
|
|||||||
</modport>
|
</modport>
|
||||||
</iface>
|
</iface>
|
||||||
<typetable fl="a0" loc="a,0,0,0,0">
|
<typetable fl="a0" loc="a,0,0,0,0">
|
||||||
<basicdtype fl="d31" loc="d,31,26,31,27" id="5" name="logic" left="31" right="0"/>
|
|
||||||
<basicdtype fl="d8" loc="d,8,4,8,11" id="6" name="integer" left="31" right="0"/>
|
<basicdtype fl="d8" loc="d,8,4,8,11" id="6" name="integer" left="31" right="0"/>
|
||||||
<basicdtype fl="d14" loc="d,14,11,14,17" id="1" name="logic"/>
|
<basicdtype fl="d14" loc="d,14,11,14,17" id="1" name="logic"/>
|
||||||
<basicdtype fl="d21" loc="d,21,7,21,12" id="8" name="logic"/>
|
<basicdtype fl="d21" loc="d,21,7,21,12" id="8" name="logic"/>
|
||||||
@ -69,11 +68,12 @@
|
|||||||
<memberdtype fl="d24" loc="d,24,16,24,20" id="15" name="data" tag="data" sub_dtype_id="11"/>
|
<memberdtype fl="d24" loc="d,24,16,24,20" id="15" name="data" tag="data" sub_dtype_id="11"/>
|
||||||
</structdtype>
|
</structdtype>
|
||||||
<ifacerefdtype fl="d29" loc="d,29,8,29,12" id="3" modportname=""/>
|
<ifacerefdtype fl="d29" loc="d,29,8,29,12" id="3" modportname=""/>
|
||||||
|
<basicdtype fl="d31" loc="d,31,27,31,28" id="5" name="logic" left="31" right="0"/>
|
||||||
<refdtype fl="d31" loc="d,31,4,31,13" id="16" name="my_struct" sub_dtype_id="2"/>
|
<refdtype fl="d31" loc="d,31,4,31,13" id="16" name="my_struct" sub_dtype_id="2"/>
|
||||||
<unpackarraydtype fl="d31" loc="d,31,26,31,27" id="4" sub_dtype_id="2">
|
<unpackarraydtype fl="d31" loc="d,31,26,31,27" id="4" sub_dtype_id="2">
|
||||||
<range fl="d31" loc="d,31,26,31,27">
|
<range fl="d31" loc="d,31,26,31,27">
|
||||||
<const fl="d31" loc="d,31,26,31,27" name="32'h1" dtype_id="5"/>
|
<const fl="d31" loc="d,31,27,31,28" name="32'h1" dtype_id="5"/>
|
||||||
<const fl="d31" loc="d,31,26,31,27" name="32'h0" dtype_id="5"/>
|
<const fl="d31" loc="d,31,27,31,28" name="32'h0" dtype_id="5"/>
|
||||||
</range>
|
</range>
|
||||||
</unpackarraydtype>
|
</unpackarraydtype>
|
||||||
<basicdtype fl="d35" loc="d,35,21,35,27" id="7" name="string"/>
|
<basicdtype fl="d35" loc="d,35,21,35,27" id="7" name="string"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user