forked from github/verilator
Fix ordering of arrayed cell wide connections, bug1202 partial.
This commit is contained in:
parent
3dacd87dfb
commit
9d055f8c13
2
Changes
2
Changes
@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 3.911 devel
|
||||
|
||||
*** Fix ordering of arrayed cell wide connections, bug1202 partial. [Mike Popoloski]
|
||||
|
||||
**** Fix enum ranges without colons, bug1204. [Mike Popoloski]
|
||||
|
||||
|
||||
|
@ -127,15 +127,18 @@ public:
|
||||
setOp2p(new AstConst(fl,range.hi())); setOp3p(new AstConst(fl,range.lo()));
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Range)
|
||||
AstNode* msbp() const { return op2p(); } // op2 = Msb expression
|
||||
AstNode* lsbp() const { return op3p(); } // op3 = Lsb expression
|
||||
AstNode* msbp() const { return op2p(); } // op2 = Msb expression
|
||||
AstNode* lsbp() const { return op3p(); } // op3 = Lsb expression
|
||||
AstNode* leftp() const { return littleEndian()?lsbp():msbp(); } // How to show a declaration
|
||||
AstNode* rightp() const { return littleEndian()?msbp():lsbp(); }
|
||||
int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; }
|
||||
bool littleEndian() const { return m_littleEndian; }
|
||||
void littleEndian(bool flag) { m_littleEndian=flag; }
|
||||
int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; }
|
||||
int leftConst() const { AstConst* constp=leftp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int rightConst() const { AstConst* constp=rightp()->castConst(); return (constp?constp->toSInt():0); }
|
||||
int leftToRightInc() const { return littleEndian()?1:-1; }
|
||||
bool littleEndian() const { return m_littleEndian; }
|
||||
void littleEndian(bool flag) { m_littleEndian=flag; }
|
||||
virtual void dump(ostream& str);
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
|
@ -218,8 +218,7 @@ class InstDeVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||
int m_instNum; // Current instantiation number
|
||||
int m_instLsb; // Current instantiation number
|
||||
int m_instSelNum; // Current instantiation count 0..N-1
|
||||
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
|
||||
|
||||
typedef map<string,AstVar*> VarNameMap;
|
||||
@ -278,8 +277,10 @@ private:
|
||||
&& ifaceVarp->dtypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType();
|
||||
|
||||
// Make all of the required clones
|
||||
m_instLsb = m_cellRangep->lsbConst();
|
||||
for (m_instNum = m_instLsb; m_instNum<=m_cellRangep->msbConst(); m_instNum++) {
|
||||
for (int i = 0; i < m_cellRangep->elementsConst(); i++) {
|
||||
m_instSelNum = m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
|
||||
int instNum = m_cellRangep->lsbConst() + i;
|
||||
|
||||
AstCell* newp = nodep->cloneTree(false);
|
||||
nodep->addNextHere(newp);
|
||||
// Remove ranging and fix name
|
||||
@ -287,8 +288,8 @@ private:
|
||||
// Somewhat illogically, we need to rename the orignal name of the cell too.
|
||||
// as that is the name users expect for dotting
|
||||
// The spec says we add [x], but that won't work in C...
|
||||
newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
|
||||
newp->origName(newp->origName()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
|
||||
newp->name(newp->name()+"__BRA__"+cvtToStr(instNum)+"__KET__");
|
||||
newp->origName(newp->origName()+"__BRA__"+cvtToStr(instNum)+"__KET__");
|
||||
UINFO(8," CELL loop "<<newp<<endl);
|
||||
|
||||
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
|
||||
@ -302,8 +303,8 @@ private:
|
||||
arrdtype->addNextHere(ifaceRefp);
|
||||
ifaceRefp->cellp(newp);
|
||||
ifaceRefp->cellName(newp->name());
|
||||
varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(m_instNum) + "__KET__");
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(m_instNum) + "__KET__");
|
||||
varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
||||
varNewp->dtypep(ifaceRefp);
|
||||
newp->addNextHere(varNewp);
|
||||
if (debug()==9) { varNewp->dumpTree(cout, "newintf: "); cout << endl; }
|
||||
@ -343,7 +344,7 @@ private:
|
||||
// Connection to array, where array dimensions match the instant dimension
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
exprp = new AstArraySel (exprp->fileline(), exprp,
|
||||
(m_instNum-m_instLsb));
|
||||
m_instSelNum);
|
||||
nodep->exprp(exprp);
|
||||
} else if (expwidth == pinwidth) {
|
||||
// NOP: Arrayed instants: widths match so connect to each instance
|
||||
@ -358,7 +359,7 @@ private:
|
||||
// Note spec allows more complicated matches such as slices and such
|
||||
}
|
||||
exprp = new AstSel (exprp->fileline(), exprp,
|
||||
pinwidth*(m_instNum-m_instLsb),
|
||||
pinwidth*m_instSelNum,
|
||||
pinwidth);
|
||||
nodep->exprp(exprp);
|
||||
} else {
|
||||
@ -457,8 +458,7 @@ public:
|
||||
// CONSTUCTORS
|
||||
explicit InstDeVisitor(AstNetlist* nodep) {
|
||||
m_cellRangep=NULL;
|
||||
m_instNum=0;
|
||||
m_instLsb=0;
|
||||
m_instSelNum=0;
|
||||
//
|
||||
nodep->accept(*this);
|
||||
}
|
||||
|
18
test_regress/t/t_interface_array_nocolon.pl
Executable file
18
test_regress/t/t_interface_array_nocolon.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;
|
64
test_regress/t/t_interface_array_nocolon.v
Normal file
64
test_regress/t/t_interface_array_nocolon.v
Normal file
@ -0,0 +1,64 @@
|
||||
// DESCRIPTION: Verilator: Functionally demonstrate an array of interfaces
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Mike Popoloski.
|
||||
|
||||
interface foo_intf
|
||||
(
|
||||
input x
|
||||
);
|
||||
endinterface
|
||||
|
||||
module foo_subm
|
||||
(
|
||||
input x
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t ();
|
||||
|
||||
localparam N = 3;
|
||||
|
||||
wire [2:0] X = 3'b110;
|
||||
|
||||
// Should not cause LITENDIAN warning?
|
||||
// verilator lint_off LITENDIAN
|
||||
foo_intf foos [N] (.x(X));
|
||||
foo_intf fool [1:3] (.x(X));
|
||||
foo_intf foom [3:1] (.x(X));
|
||||
|
||||
foo_subm subs [N] (.x(X));
|
||||
foo_subm subl [1:3] (.x(X));
|
||||
foo_subm subm [3:1] (.x(X));
|
||||
|
||||
initial begin
|
||||
// Check numbering with 0 first
|
||||
// NC has a bug here
|
||||
if (foos[0].x !== 1'b1) $stop;
|
||||
if (foos[1].x !== 1'b1) $stop;
|
||||
if (foos[2].x !== 1'b0) $stop;
|
||||
//
|
||||
if (fool[1].x !== 1'b1) $stop;
|
||||
if (fool[2].x !== 1'b1) $stop;
|
||||
if (fool[3].x !== 1'b0) $stop;
|
||||
//
|
||||
if (foom[1].x !== 1'b0) $stop;
|
||||
if (foom[2].x !== 1'b1) $stop;
|
||||
if (foom[3].x !== 1'b1) $stop;
|
||||
//
|
||||
if (subs[0].x !== 1'b1) $stop;
|
||||
if (subs[1].x !== 1'b1) $stop;
|
||||
if (subs[2].x !== 1'b0) $stop;
|
||||
//
|
||||
if (subl[1].x !== 1'b1) $stop;
|
||||
if (subl[2].x !== 1'b1) $stop;
|
||||
if (subl[3].x !== 1'b0) $stop;
|
||||
//
|
||||
if (subm[1].x !== 1'b0) $stop;
|
||||
if (subm[2].x !== 1'b1) $stop;
|
||||
if (subm[3].x !== 1'b1) $stop;
|
||||
//
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user