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; }
|
||||
};
|
||||
|
||||
class AstAssocRange : public AstNodeRange {
|
||||
// Associative array range specification
|
||||
// Only for early parsing - becomes AstAssocDType
|
||||
class AstBracketRange : public AstNodeRange {
|
||||
// Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range,
|
||||
// unknown until lhsp type is determined
|
||||
public:
|
||||
AstAssocRange(FileLine* fl, AstNodeDType* dtp)
|
||||
AstBracketRange(FileLine* fl, AstNode* elementsp)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
setOp1p(dtp);
|
||||
setOp1p(elementsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(AssocRange)
|
||||
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)
|
||||
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; }
|
||||
// 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 {
|
||||
@ -568,6 +558,36 @@ public:
|
||||
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 {
|
||||
// Dynamic array data type, ie "[]"
|
||||
// Children: DTYPE (moved to refDTypep() in V3Width)
|
||||
|
@ -181,6 +181,12 @@ private:
|
||||
if (AstUnpackArrayDType* adtypep = VN_CAST(nodep, UnpackArrayDType)) {
|
||||
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;
|
||||
}
|
||||
void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
|
||||
|
@ -120,8 +120,6 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
|
||||
if (rangep && isPacked) {
|
||||
arrayp
|
||||
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
||||
} else if (VN_IS(nrangep, QueueRange)) {
|
||||
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
|
||||
} else if (rangep
|
||||
&& (VN_IS(rangep->leftp(), Unbounded)
|
||||
|| VN_IS(rangep->rightp(), Unbounded))) {
|
||||
@ -132,12 +130,11 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
|
||||
rangep);
|
||||
} else if (VN_IS(nrangep, UnsizedRange)) {
|
||||
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
|
||||
} else if (VN_IS(nrangep, AssocRange)) {
|
||||
AstAssocRange* arangep = VN_CAST(nrangep, AssocRange);
|
||||
AstNodeDType* keyp = arangep->keyDTypep();
|
||||
keyp->unlinkFrBack();
|
||||
arrayp
|
||||
= new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
|
||||
} else if (VN_IS(nrangep, BracketRange)) {
|
||||
AstBracketRange* arangep = VN_CAST(nrangep, BracketRange);
|
||||
AstNode* keyp = arangep->elementsp()->unlinkFrBack();
|
||||
arrayp = new AstBracketArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp,
|
||||
keyp);
|
||||
} else {
|
||||
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
||||
}
|
||||
|
@ -1061,7 +1061,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstUnbounded* nodep) VL_OVERRIDE {
|
||||
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())) {
|
||||
nodep->v3error("Unsupported/illegal unbounded ('$') in this context.");
|
||||
}
|
||||
@ -1354,6 +1354,35 @@ private:
|
||||
nodep->dtypep(nodep); // The array itself, not subDtype
|
||||
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 {
|
||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||
@ -1432,6 +1461,10 @@ private:
|
||||
}
|
||||
userIterateChildren(nodep, NULL);
|
||||
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->typedefp(NULL); // Note until line above subDTypep() may have followed this
|
||||
// Widths are resolved, but special iterate to check for recurstion
|
||||
@ -4979,6 +5012,9 @@ private:
|
||||
}
|
||||
if (!dtnodep->didWidth()) {
|
||||
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);
|
||||
UASSERT_OBJ(dtnodep->didWidth(), parentp,
|
||||
"iterateEditMoveDTypep didn't get width resolution");
|
||||
|
@ -1962,11 +1962,10 @@ variable_dimension<rangep>: // ==IEEE: variable_dimension
|
||||
'[' ']' { $$ = new AstUnsizedRange($1); }
|
||||
// // IEEE: unpacked_dimension
|
||||
| anyrange { $$ = $1; }
|
||||
| '[' constExpr ']' { if (VN_IS($2, Unbounded)) { $2->deleteTree(); $$ = new AstQueueRange($1); }
|
||||
else { $$ = new AstRange($1, new AstConst($1, 0),
|
||||
new AstSub($1, $2, new AstConst($1, 1))); } }
|
||||
// // IEEE: associative_dimension
|
||||
| '[' data_type ']' { $$ = new AstAssocRange($1, $2); }
|
||||
// // IEEE: unpacked_dimension (if const_expr)
|
||||
// // IEEE: associative_dimension (if data_type)
|
||||
// // Can't tell which until see if expr is data type or not
|
||||
| '[' exprOrDataType ']' { $$ = new AstBracketRange($1, $2); }
|
||||
| yP_BRASTAR ']' { $$ = NULL; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); }
|
||||
| '[' '*' ']' { $$ = NULL; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); }
|
||||
// // 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>
|
||||
</iface>
|
||||
<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="d14" loc="d,14,11,14,17" id="1" 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"/>
|
||||
</structdtype>
|
||||
<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"/>
|
||||
<unpackarraydtype fl="d31" loc="d,31,26,31,27" id="4" sub_dtype_id="2">
|
||||
<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,26,31,27" name="32'h0" dtype_id="5"/>
|
||||
<const fl="d31" loc="d,31,27,31,28" name="32'h1" dtype_id="5"/>
|
||||
<const fl="d31" loc="d,31,27,31,28" name="32'h0" dtype_id="5"/>
|
||||
</range>
|
||||
</unpackarraydtype>
|
||||
<basicdtype fl="d35" loc="d,35,21,35,27" id="7" name="string"/>
|
||||
|
Loading…
Reference in New Issue
Block a user