mirror of
https://github.com/verilator/verilator.git
synced 2025-07-31 07:56:10 +00:00
Support genvar indexes into arrayed cells, bug517.
This commit is contained in:
parent
b16ea8b719
commit
040b1b06d5
2
Changes
2
Changes
@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
** Add --vpi flag, and fix VPI linkage, bug969. [Arthur Kahlich]
|
||||
|
||||
** Support genvar indexes into arrayed cells, bug517. [Todd Strader]
|
||||
|
||||
** Support $sformatf, bug977. [Johan Bjork]
|
||||
|
||||
**** Add VerilatedScopeNameMap for introspection, bug966. [Todd Strader]
|
||||
|
@ -1311,6 +1311,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(VarXRef, VARXREF)
|
||||
virtual void dump(ostream& str);
|
||||
string dotted() const { return m_dotted; }
|
||||
void dotted(const string& dotted) { m_dotted = dotted; }
|
||||
string prettyDotted() const { return prettyName(dotted()); }
|
||||
string inlinedDots() const { return m_inlinedDots; }
|
||||
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
|
||||
@ -1570,6 +1571,56 @@ public:
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
};
|
||||
|
||||
class AstCellRef : public AstNode {
|
||||
// As-of-yet unlinkable reference into a cell
|
||||
private:
|
||||
string m_name; // Cell name
|
||||
public:
|
||||
AstCellRef(FileLine* fl,
|
||||
string name, AstNode* cellp, AstNode* exprp)
|
||||
: AstNode(fl)
|
||||
, m_name(name) {
|
||||
addNOp1p(cellp); addNOp2p(exprp); }
|
||||
ASTNODE_NODE_FUNCS(CellRef, CELLREF)
|
||||
// ACCESSORS
|
||||
virtual string name() const { return m_name; } // * = Array name
|
||||
AstNode* cellp() const { return op1p(); } // op1 = Cell
|
||||
AstNode* exprp() const { return op2p(); } // op2 = Expression
|
||||
};
|
||||
|
||||
class AstCellArrayRef : public AstNode {
|
||||
// As-of-yet unlinkable reference into an array of cells
|
||||
private:
|
||||
string m_name; // Array name
|
||||
public:
|
||||
AstCellArrayRef(FileLine* fl,
|
||||
string name, AstNode* selectExprp)
|
||||
: AstNode(fl)
|
||||
, m_name(name) {
|
||||
addNOp1p(selectExprp); }
|
||||
ASTNODE_NODE_FUNCS(CellArrayRef, CELLARRAYREF)
|
||||
// ACCESSORS
|
||||
virtual string name() const { return m_name; } // * = Array name
|
||||
AstNode* selp() const { return op1p(); } // op1 = Select expression
|
||||
};
|
||||
|
||||
class AstUnlinkedVarXRef : public AstNode {
|
||||
// As-of-yet unlinkable VarXRef
|
||||
private:
|
||||
string m_name; // Var name
|
||||
public:
|
||||
AstUnlinkedVarXRef(FileLine* fl,
|
||||
AstVarXRef* vxrp, string name, AstNode* crp)
|
||||
: AstNode(fl)
|
||||
, m_name(name) {
|
||||
addNOp1p(vxrp); addNOp2p(crp); }
|
||||
ASTNODE_NODE_FUNCS(UnlinkedVarXRef, UNLINKEDVARXREF)
|
||||
// ACCESSORS
|
||||
virtual string name() const { return m_name; } // * = Var name
|
||||
AstVarXRef* varxrefp() const { return op1p()->castVarXRef(); } // op1 = VarXRef
|
||||
AstNode* cellrefp() const { return op2p(); } // op1 = CellArrayRef or CellRef
|
||||
};
|
||||
|
||||
class AstBind : public AstNode {
|
||||
// Parents: MODULE
|
||||
// Children: CELL
|
||||
|
@ -1446,7 +1446,7 @@ private:
|
||||
}
|
||||
m_selp = NULL;
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||
bool did=false;
|
||||
|
@ -348,14 +348,18 @@ private:
|
||||
// This is quite similar to how classes work; when unpacked classes are better supported
|
||||
// may remap interfaces to be more like a class.
|
||||
if (!nodep->hasIfaceVar()) {
|
||||
string varName = nodep->name()+"__Viftop"; // V3LinkDot looks for this naming
|
||||
AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
|
||||
idtypep->cellp(nodep); // Only set when real parent cell known
|
||||
idtypep->ifacep(NULL); // cellp overrides
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
|
||||
varp->isIfaceParent(true);
|
||||
nodep->addNextHere(varp);
|
||||
nodep->hasIfaceVar(true);
|
||||
if (!nodep->rangep()) {
|
||||
string varName = nodep->name() + "__Viftop"; // V3LinkDot looks for this naming
|
||||
AstIfaceRefDType *idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(),
|
||||
nodep->modp()->name());
|
||||
idtypep->cellp(nodep); // Only set when real parent cell known
|
||||
idtypep->ifacep(NULL); // cellp overrides
|
||||
AstVar *varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
|
||||
VFlagChildDType(), idtypep);
|
||||
varp->isIfaceParent(true);
|
||||
nodep->addNextHere(varp);
|
||||
nodep->hasIfaceVar(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->modp()) {
|
||||
|
@ -1322,12 +1322,15 @@ private:
|
||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
|
||||
AstDot* m_dotp; // Current dot
|
||||
bool m_unresolved; // Unresolved, needs help from V3Param
|
||||
AstNode* m_unlinkedScope;// Unresolved scope, needs corresponding VarXRef
|
||||
bool m_dotErr; // Error found in dotted resolution, ignore upwards
|
||||
string m_dotText; // String of dotted names found in below parseref
|
||||
DotStates() { init(NULL); }
|
||||
~DotStates() {}
|
||||
void init(VSymEnt* curSymp) {
|
||||
m_dotPos = DP_NONE; m_dotSymp = curSymp; m_dotp = NULL; m_dotErr = false; m_dotText = "";
|
||||
m_unresolved = false; m_unlinkedScope = NULL;
|
||||
}
|
||||
string ascii() const {
|
||||
static const char* names[] = { "NONE","PACKAGE","SCOPE","FINAL","MEMBER" };
|
||||
@ -1335,6 +1338,7 @@ private:
|
||||
sstr<<"ds="<<names[m_dotPos];
|
||||
sstr<<" dse"<<(void*)m_dotSymp;
|
||||
sstr<<" txt="<<m_dotText;
|
||||
sstr<<" unr="<<m_unresolved;
|
||||
return sstr.str();
|
||||
}
|
||||
} m_ds; // State to preserve across recursions
|
||||
@ -1505,6 +1509,9 @@ private:
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
//if (debug()>=9) nodep->dumpTree("-dot-lho: ");
|
||||
}
|
||||
if (m_ds.m_unresolved && (nodep->lhsp()->castCellRef() || nodep->lhsp()->castCellArrayRef())) {
|
||||
m_ds.m_unlinkedScope = nodep->lhsp();
|
||||
}
|
||||
if (!m_ds.m_dotErr) { // Once something wrong, give up
|
||||
if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_FINAL; // Top 'final' dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
@ -1523,6 +1530,10 @@ private:
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
} else { // Dot midpoint
|
||||
AstNode* newp = nodep->rhsp()->unlinkFrBack();
|
||||
if (m_ds.m_unresolved) {
|
||||
AstCellRef* crp = new AstCellRef(nodep->fileline(), nodep->name(), nodep->lhsp()->unlinkFrBack(), newp);
|
||||
newp = crp;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
@ -1641,17 +1652,24 @@ private:
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
else if (allowVar) {
|
||||
AstNodeVarRef* newp;
|
||||
AstNode* newp;
|
||||
if (m_ds.m_dotText != "") {
|
||||
newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later
|
||||
newp->varp(varp);
|
||||
AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later
|
||||
refp->varp(varp);
|
||||
m_ds.m_dotText = "";
|
||||
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
|
||||
newp = new AstUnlinkedVarXRef(nodep->fileline(), refp->castVarXRef(), refp->name(), m_ds.m_unlinkedScope->unlinkFrBack());
|
||||
m_ds.m_unlinkedScope = NULL;
|
||||
m_ds.m_unresolved = false;
|
||||
} else {
|
||||
newp = refp;
|
||||
}
|
||||
} else {
|
||||
newp = new AstVarRef(nodep->fileline(), nodep->name(), false); // lvalue'ness computed later
|
||||
newp->varp(varp);
|
||||
newp->packagep(foundp->packagep());
|
||||
UINFO(9," new "<<newp<<endl);
|
||||
AstVarRef* refp = new AstVarRef(nodep->fileline(), varp, false); // lvalue'ness computed later
|
||||
refp->packagep(foundp->packagep());
|
||||
newp = refp;
|
||||
}
|
||||
UINFO(9," new "<<newp<<endl);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
m_ds.m_dotPos = DP_MEMBER;
|
||||
ok = true;
|
||||
@ -1906,12 +1924,9 @@ private:
|
||||
if (nodep->user3SetOnce()) return;
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
if (AstConst* constp = nodep->rhsp()->castConst()) {
|
||||
string index = AstNode::encodeNumber(constp->toSInt());
|
||||
m_ds.m_dotText += "__BRA__"+index+"__KET__";
|
||||
} else {
|
||||
nodep->v3error("Unsupported: Non-constant inside []'s in the cell part of a dotted reference");
|
||||
}
|
||||
UINFO(9," deferring until after a V3Param pass: "<<nodep<<endl);
|
||||
m_ds.m_dotText += "__BRA__??__KET__";
|
||||
m_ds.m_unresolved = true;
|
||||
// And pass up m_ds.m_dotText
|
||||
}
|
||||
// Pass dot state down to fromp()
|
||||
@ -1923,6 +1938,11 @@ private:
|
||||
nodep->attrp()->iterateAndNext(*this);
|
||||
}
|
||||
m_ds = lastStates;
|
||||
if (m_ds.m_unresolved && m_ds.m_dotPos == DP_SCOPE) {
|
||||
AstNode* exprp = nodep->bitp()->unlinkFrBack();
|
||||
AstCellArrayRef* newp = new AstCellArrayRef(nodep->fileline(), nodep->fromp()->name(), exprp);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
// Excludes simple AstSelBit, see above
|
||||
@ -2018,6 +2038,18 @@ private:
|
||||
checkNoDot(nodep);
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstCellRef* nodep, AstNUser*) {
|
||||
UINFO(5," AstCellRef: "<<nodep<<" "<<m_ds.ascii()<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstCellArrayRef* nodep, AstNUser*) {
|
||||
UINFO(5," AstCellArrayRef: "<<nodep<<" "<<m_ds.ascii()<<endl);
|
||||
// Expression already iterated
|
||||
}
|
||||
virtual void visit(AstUnlinkedVarXRef* nodep, AstNUser*) {
|
||||
UINFO(5," AstCellArrayRef: "<<nodep<<" "<<m_ds.ascii()<<endl);
|
||||
// No need to iterate, if we have a UnlinkedVarXRef, we're already done
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
checkNoDot(nodep);
|
||||
|
@ -211,6 +211,14 @@ private:
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstCellArrayRef* nodep, AstNUser*) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{ // selp is not an lvalue
|
||||
m_setRefLvalue = false;
|
||||
nodep->selp()->iterateAndNext(*this);
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{ // Only set lvalues on the from
|
||||
|
@ -204,6 +204,9 @@ private:
|
||||
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 (AstUnlinkedVarXRef* uvxrp = basefromp->castUnlinkedVarXRef()) { // Maybe varxref - so need to clone
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||
uvxrp->cloneTree(false)));
|
||||
} else if (AstMemberSel* fromp = basefromp->castMemberSel()) {
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::MEMBER_BASE,
|
||||
fromp->cloneTree(false)));
|
||||
|
@ -108,6 +108,8 @@ private:
|
||||
typedef deque<AstCell*> CellList;
|
||||
CellList m_cellps; // Cells left to process (in this module)
|
||||
|
||||
string m_unlinkedTxt; // Text for AstUnlinkedVarXRef
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
@ -251,6 +253,41 @@ private:
|
||||
virtual void visit(AstVarXRef* nodep, AstNUser*) {
|
||||
nodep->varp(NULL); // Needs relink, as may remove pointed-to var
|
||||
}
|
||||
virtual void visit(AstUnlinkedVarXRef* nodep, AstNUser*) {
|
||||
m_unlinkedTxt.clear();
|
||||
nodep->cellrefp()->iterate(*this);
|
||||
nodep->varxrefp()->dotted(m_unlinkedTxt);
|
||||
nodep->replaceWith(nodep->varxrefp()->unlinkFrBack());
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstCellArrayRef* nodep, AstNUser*) {
|
||||
V3Const::constifyParamsEdit(nodep->selp());
|
||||
if (AstConst* constp = nodep->selp()->castConst()) {
|
||||
string index = AstNode::encodeNumber(constp->toSInt());
|
||||
m_unlinkedTxt += nodep->name() + "__BRA__"+index+"__KET__";
|
||||
} else {
|
||||
nodep->v3error("Could not expand constant selection inside dotted reference: "<<nodep->selp()->prettyName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCellRef* nodep, AstNUser*) {
|
||||
// Children must be CellArrayRef, CellRef or ParseRef
|
||||
if (nodep->cellp()->castCellArrayRef() || nodep->cellp()->castCellRef()) {
|
||||
nodep->cellp()->iterate(*this);
|
||||
} else if (nodep->cellp()->castParseRef()) {
|
||||
m_unlinkedTxt += nodep->cellp()->name();
|
||||
} else {
|
||||
nodep->v3error("Could not elaborate dotted reference (LHS): "<<nodep->cellp()->prettyName());
|
||||
}
|
||||
m_unlinkedTxt += ".";
|
||||
if (nodep->exprp()->castCellArrayRef() || nodep->exprp()->castCellRef()) {
|
||||
nodep->exprp()->iterate(*this);
|
||||
} else if (nodep->exprp()->castParseRef()) {
|
||||
m_unlinkedTxt += nodep->exprp()->name();
|
||||
} else {
|
||||
nodep->v3error("Could not elaborate dotted reference (RHS): "<<nodep->exprp()->prettyName());
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Statements
|
||||
virtual void visit(AstGenerate* nodep, AstNUser*) {
|
||||
|
18
test_regress/t/t_crazy_sel.pl
Executable file
18
test_regress/t/t_crazy_sel.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 (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
42
test_regress/t/t_crazy_sel.v
Normal file
42
test_regress/t/t_crazy_sel.v
Normal file
@ -0,0 +1,42 @@
|
||||
// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference
|
||||
// as the select expression
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Todd Strader.
|
||||
|
||||
interface foo_intf;
|
||||
logic a;
|
||||
endinterface
|
||||
|
||||
function integer the_other_func (input integer val);
|
||||
return val;
|
||||
endfunction
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
genvar the_genvar;
|
||||
generate
|
||||
for (the_genvar = 0; the_genvar < 4; the_genvar++) begin: foo_loop
|
||||
foo foo_inst();
|
||||
end
|
||||
endgenerate
|
||||
|
||||
bar bar_inst();
|
||||
|
||||
logic x;
|
||||
assign x = foo_loop[bar_inst.THE_LP].foo_inst.y;
|
||||
//localparam N = 2;
|
||||
//assign x = foo_loop[N].foo_inst.y;
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module foo();
|
||||
logic y;
|
||||
endmodule
|
||||
|
||||
module bar();
|
||||
localparam THE_LP = 2;
|
||||
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, bug517");
|
||||
|
||||
# Compile time only test
|
||||
compile (
|
||||
);
|
||||
|
18
test_regress/t/t_genfor_hier.pl
Executable file
18
test_regress/t/t_genfor_hier.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 (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
23
test_regress/t/t_genfor_hier.v
Normal file
23
test_regress/t/t_genfor_hier.v
Normal file
@ -0,0 +1,23 @@
|
||||
// DESCRIPTION: Verilator: Demonstrate deferred linking across module
|
||||
// bondaries
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Todd Strader.
|
||||
|
||||
module m1();
|
||||
logic v1;
|
||||
endmodule
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
for (genvar the_genvar = 0; the_genvar < 4; the_genvar++) begin : m1_b
|
||||
m1 m1_inst();
|
||||
end
|
||||
for (genvar the_other_genvar = 0; the_other_genvar < 4; the_other_genvar++) begin
|
||||
always_comb m1_b[the_other_genvar].m1_inst.v1 = 1'b0;
|
||||
end
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
18
test_regress/t/t_interface_array.pl
Executable file
18
test_regress/t/t_interface_array.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 (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
79
test_regress/t/t_interface_array.v
Normal file
79
test_regress/t/t_interface_array.v
Normal file
@ -0,0 +1,79 @@
|
||||
// DESCRIPTION: Verilator: Functionally demonstrate an array of interfaces
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Todd Strader.
|
||||
|
||||
interface foo_intf;
|
||||
logic a;
|
||||
|
||||
modport source (
|
||||
output a
|
||||
);
|
||||
|
||||
modport sink (
|
||||
input a
|
||||
);
|
||||
endinterface
|
||||
|
||||
function integer identity (input integer val);
|
||||
return val;
|
||||
endfunction
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
localparam N = 5;
|
||||
|
||||
logic [N-1:0] a_in;
|
||||
logic [N-1:0] a_out;
|
||||
logic [N-1:0] ack_out;
|
||||
|
||||
foo_intf foos [N-1:0] ();
|
||||
|
||||
// Deferred link dotting with genvars
|
||||
generate
|
||||
genvar i;
|
||||
for (i = 0; i < N-4; i++) begin : someLoop
|
||||
assign ack_out[i] = a_in[i];
|
||||
assign foos[i].a = a_in[i];
|
||||
assign a_out[i] = foos[i].a;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Defferred link dotting with localparam
|
||||
localparam THE_LP = N-3;
|
||||
assign ack_out[THE_LP] = a_in[THE_LP];
|
||||
assign foos[THE_LP].a = a_in[THE_LP];
|
||||
assign a_out[THE_LP] = foos[THE_LP].a;
|
||||
|
||||
// Defferred link dotting with arithmetic expression
|
||||
assign ack_out[N-2] = a_in[N-2];
|
||||
assign foos[N-2].a = a_in[N-2];
|
||||
assign a_out[N-2] = foos[N-2].a;
|
||||
|
||||
// Defferred link dotting with funcrefs
|
||||
assign ack_out[identity(N-1)] = a_in[identity(N-1)];
|
||||
assign foos[identity(N-1)].a = a_in[identity(N-1)];
|
||||
assign a_out[identity(N-1)] = foos[identity(N-1)].a;
|
||||
|
||||
initial a_in = '0;
|
||||
always @(posedge clk) begin
|
||||
a_in <= a_in + { {N-1 {1'b0}}, 1'b1 };
|
||||
|
||||
if (ack_out != a_out) begin
|
||||
$display("%%Error: Interface and non-interface paths do not match: 0b%b 0b%b",
|
||||
ack_out, a_out);
|
||||
$stop;
|
||||
end
|
||||
|
||||
if (& a_in) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
21
test_regress/t/t_interface_array_bad.pl
Executable file
21
test_regress/t/t_interface_array_bad.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/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_interface_array_bad.v:\d+: Expecting expression to be constant, but variable isn\'t const: bar
|
||||
%Error: t/t_interface_array_bad.v:\d+: Could not expand constant selection inside dotted reference: bar
|
||||
%Error: t/t_interface_array_bad.v:\d+: Can\'t find definition of \'a\' in dotted signal: .a
|
||||
%Error: Known scopes under \'a\':.*
|
||||
%Error: Exiting due to.*',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
53
test_regress/t/t_interface_array_bad.v
Normal file
53
test_regress/t/t_interface_array_bad.v
Normal file
@ -0,0 +1,53 @@
|
||||
// DESCRIPTION: Verilator: Demonstrate deferred linking error messages
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Todd Strader.
|
||||
|
||||
interface foo_intf;
|
||||
logic a;
|
||||
endinterface
|
||||
|
||||
function integer the_other_func (input integer val);
|
||||
return val;
|
||||
endfunction
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
localparam N = 4;
|
||||
|
||||
foo_intf foos [N-1:0] ();
|
||||
logic [ 7 : 0 ] bar;
|
||||
|
||||
// Non-constant dotted select is not allowed
|
||||
assign foos[bar].a = 1'b1;
|
||||
|
||||
baz baz_inst ();
|
||||
|
||||
// Unsure how to produce V3Param AstCellRef visitor errors
|
||||
//assign baz_inst.x = 1'b1;
|
||||
//assign baz_inst.N = 1'b1;
|
||||
//assign baz_inst.7 = 1'b1;
|
||||
//assign baz_inst.qux_t = 1'b1;
|
||||
//assign baz_inst.the_func = 1'b1;
|
||||
//assign baz_inst.the_lp = 1'b1;
|
||||
|
||||
//assign bar.x = 1'b1;
|
||||
//assign fake_inst.x = 1'b1;
|
||||
//assign the_other_func.x = 1'b1;
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module baz;
|
||||
typedef integer qux_t;
|
||||
|
||||
function integer the_func (input integer val);
|
||||
return val;
|
||||
endfunction
|
||||
|
||||
localparam the_lp = 5;
|
||||
endmodule
|
20
test_regress/t/t_interface_array_modport.pl
Executable file
20
test_regress/t/t_interface_array_modport.pl
Executable file
@ -0,0 +1,20 @@
|
||||
#!/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.
|
||||
|
||||
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug978");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
35
test_regress/t/t_interface_array_modport.v
Normal file
35
test_regress/t/t_interface_array_modport.v
Normal file
@ -0,0 +1,35 @@
|
||||
// DESCRIPTION: Verilator: Connecting an interface array slice to a module's portmap
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Todd Strader.
|
||||
|
||||
interface foo_intf;
|
||||
logic a;
|
||||
endinterface
|
||||
|
||||
module foo_mod
|
||||
(
|
||||
foo_intf foo
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
localparam N = 4;
|
||||
|
||||
foo_intf foos [N-1:0] ();
|
||||
//foo_intf foos ();
|
||||
|
||||
foo_mod
|
||||
foo_mod
|
||||
(
|
||||
.foo (foos[2])
|
||||
//.foo (foos)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user