Fix tristate connection to unconnected input, bug494, bug495.
This commit is contained in:
parent
c75de0f37c
commit
40f4411b69
|
|
@ -115,7 +115,7 @@ private:
|
||||||
// this loop as it clone()s itself.
|
// this loop as it clone()s itself.
|
||||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
||||||
if (!pinp->exprp()) continue;
|
if (!pinp->exprp()) continue;
|
||||||
V3Inst::pinReconnectSimple(pinp, nodep, m_modp);
|
V3Inst::pinReconnectSimple(pinp, nodep, m_modp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone original module
|
// Clone original module
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ private:
|
||||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||||
if (!nodep->user1Inc()) {
|
if (!nodep->user1Inc()) {
|
||||||
// Simplify it
|
// Simplify it
|
||||||
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
|
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, false);
|
||||||
// Make a ASSIGNW (expr, pin)
|
// Make a ASSIGNW (expr, pin)
|
||||||
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
||||||
if (nodep->width() != nodep->modVarp()->width())
|
if (nodep->width() != nodep->modVarp()->width())
|
||||||
|
|
@ -237,7 +237,7 @@ public:
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Inst class functions
|
// Inst class functions
|
||||||
|
|
||||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule* modp) {
|
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModule* modp, bool forTristate) {
|
||||||
// If a pin connection is "simple" leave it as-is
|
// If a pin connection is "simple" leave it as-is
|
||||||
// Else create a intermediate wire to perform the interconnect
|
// Else create a intermediate wire to perform the interconnect
|
||||||
// Return the new assignment, if one was made
|
// Return the new assignment, if one was made
|
||||||
|
|
@ -261,7 +261,7 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
|
||||||
&& pinp->width() == pinVarp->width()
|
&& pinp->width() == pinVarp->width()
|
||||||
&& 1) {
|
&& 1) {
|
||||||
// Done. One to one interconnect won't need a temporary variable.
|
// Done. One to one interconnect won't need a temporary variable.
|
||||||
} else if (pinp->exprp()->castConst()) {
|
} else if (!forTristate && pinp->exprp()->castConst()) {
|
||||||
// Done. Constant.
|
// Done. Constant.
|
||||||
} else {
|
} else {
|
||||||
// Make a new temp wire
|
// Make a new temp wire
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ class V3Inst {
|
||||||
public:
|
public:
|
||||||
static void instAll(AstNetlist* nodep);
|
static void instAll(AstNetlist* nodep);
|
||||||
static void dearrayAll(AstNetlist* nodep);
|
static void dearrayAll(AstNetlist* nodep);
|
||||||
static AstAssignW* pinReconnectSimple(AstPin* nodep, AstCell* cellp, AstNodeModule* modp);
|
static AstAssignW* pinReconnectSimple(AstPin* nodep, AstCell* cellp, AstNodeModule* modp,
|
||||||
|
bool forTristate);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|
|
||||||
|
|
@ -634,7 +634,7 @@ private:
|
||||||
|
|
||||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||||
// Pin: Link to submodule's port
|
// Pin: Link to submodule's port
|
||||||
// ONLY CALLED by AstCell during ID_RESOLVE and ID_PARAM state
|
// ONLY CALLED by visit(AstCell) during ID_RESOLVE and ID_PARAM state
|
||||||
if (m_idState==ID_RESOLVE && !nodep->modVarp()) {
|
if (m_idState==ID_RESOLVE && !nodep->modVarp()) {
|
||||||
if (!m_cellVarsp) nodep->v3fatalSrc("Pin not under cell?\n");
|
if (!m_cellVarsp) nodep->v3fatalSrc("Pin not under cell?\n");
|
||||||
AstVar* refp = m_cellVarsp->findIdFlat(nodep->name())->castVar();
|
AstVar* refp = m_cellVarsp->findIdFlat(nodep->name())->castVar();
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,16 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||||
return invarp->user4p()->castNode()->castVar();
|
return invarp->user4p()->castNode()->castVar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstVar* getCreateUnconnVarp(AstNode* fromp) {
|
||||||
|
AstVar* newp = new AstVar(fromp->fileline(),
|
||||||
|
AstVarType::MODULETEMP,
|
||||||
|
"__Vtriunconn"+cvtToStr(m_unique++),
|
||||||
|
VFlagLogicPacked(), fromp->width());
|
||||||
|
if (!m_modp) { newp->v3error("Unsupported: Creating tristate signal not underneath a module"); }
|
||||||
|
else m_modp->addStmtp(newp);
|
||||||
|
return newp;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* newEnableDeposit(AstSel* selp, AstNode* enp) {
|
AstNode* newEnableDeposit(AstSel* selp, AstNode* enp) {
|
||||||
// Form a "deposit" instruction for given enable, using existing select as a template.
|
// Form a "deposit" instruction for given enable, using existing select as a template.
|
||||||
// Would be nicer if we made this a new AST type
|
// Would be nicer if we made this a new AST type
|
||||||
|
|
@ -196,6 +206,17 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||||
UINFO(9,(m_alhs?"alhs":"")<<" "<<nodep<<endl);
|
UINFO(9,(m_alhs?"alhs":"")<<" "<<nodep<<endl);
|
||||||
// Detect any Z consts and convert them to 0's with an enable that is also 0.
|
// Detect any Z consts and convert them to 0's with an enable that is also 0.
|
||||||
|
if (m_alhs && nodep->user1p()) {
|
||||||
|
// A pin with 1'b0 or similar connection results in an assign with constant on LHS
|
||||||
|
// due to the pinReconnectSimple call in visit AstPin.
|
||||||
|
// We can ignore the output override by making a temporary
|
||||||
|
AstVar* varp = getCreateUnconnVarp(nodep);
|
||||||
|
AstNode* newp = new AstVarRef(nodep->fileline(), varp, true);
|
||||||
|
UINFO(9," const->"<<newp<<endl);
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
pushDeletep(nodep); nodep = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (nodep->num().hasZ()) {
|
if (nodep->num().hasZ()) {
|
||||||
FileLine* fl = nodep->fileline();
|
FileLine* fl = nodep->fileline();
|
||||||
V3Number numz (fl,nodep->width()); numz.opBitsZ(nodep->num()); //Z->1, else 0
|
V3Number numz (fl,nodep->width()); numz.opBitsZ(nodep->num()); //Z->1, else 0
|
||||||
|
|
@ -388,7 +409,7 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||||
nodep->rhsp()->user1p(NULL);
|
nodep->rhsp()->user1p(NULL);
|
||||||
UINFO(9," enp<-rhs "<<nodep->lhsp()->user1p()<<endl);
|
UINFO(9," enp<-rhs "<<nodep->lhsp()->user1p()<<endl);
|
||||||
}
|
}
|
||||||
m_alhs = true;
|
m_alhs = true; // And user1p() will indicate tristate equation, if any
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
m_alhs = false;
|
m_alhs = false;
|
||||||
}
|
}
|
||||||
|
|
@ -467,15 +488,25 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .tri(SEL(trisig,x)) becomes
|
||||||
|
// INPUT: -> (VARREF(trisig__pinin)),
|
||||||
|
// trisig__pinin = SEL(trisig,x) // via pinReconnectSimple
|
||||||
|
// OUTPUT: -> (VARREF(trisig__pinout))
|
||||||
|
// ENABLE: -> (VARREF(trisig__pinen)
|
||||||
|
// SEL(trisig,x) = BUFIF1(enable__temp, trisig__pinen)
|
||||||
|
// Added complication is the signal may be an output/inout or just input with tie off (or not) up top
|
||||||
|
// PIN PORT NEW PORTS AND CONNECTIONS
|
||||||
|
// N/C input in(from-resolver), __out(to-resolver-only), __en(to-resolver-only)
|
||||||
|
// N/C inout Spec says illegal
|
||||||
|
// N/C output Unsupported; Illegal?
|
||||||
|
// wire input in(from-resolver-with-wire-value), __out(to-resolver-only), __en(to-resolver-only)
|
||||||
|
// wire inout in, __out, __en
|
||||||
|
// wire output in, __out, __en
|
||||||
|
// const input in(from-resolver-with-const-value), __out(to-resolver-only), __en(to-resolver-only)
|
||||||
|
// const inout Spec says illegal
|
||||||
|
// const output Unsupported; Illegal?
|
||||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||||
// .tri(SEL(trisig,x)) becomes
|
|
||||||
// INPUT: -> (VARREF(trisig__pinin)),
|
|
||||||
// trisig__pinin = SEL(trisig,x) // via pinReconnectSimple
|
|
||||||
// OUTPUT: -> (VARREF(trisig__pinout))
|
|
||||||
// ENABLE: -> (VARREF(trisig__pinen)
|
|
||||||
// SEL(trisig,x) = BUFIF1(enable__temp, trisig__pinen)
|
|
||||||
UINFO(9," "<<nodep<<endl);
|
UINFO(9," "<<nodep<<endl);
|
||||||
if (!nodep->exprp()) return; // No-connect
|
|
||||||
AstVar* enModVarp = (AstVar*) nodep->modVarp()->user1p();
|
AstVar* enModVarp = (AstVar*) nodep->modVarp()->user1p();
|
||||||
if (!enModVarp) { // no __en signals on this pin
|
if (!enModVarp) { // no __en signals on this pin
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
|
@ -488,7 +519,15 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||||
if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: ");
|
if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: ");
|
||||||
|
|
||||||
// pinReconnectSimple needs to presume input or output behavior; we need both
|
// pinReconnectSimple needs to presume input or output behavior; we need both
|
||||||
// Therefore, create the BUFIF1 on output and separate input pin, then pinReconnectSimple both
|
// Therefore, create the enable, output and separate input pin, then pinReconnectSimple all
|
||||||
|
|
||||||
|
if (!nodep->exprp()) { // No-connect; covert to empty connection
|
||||||
|
UINFO(5,"Unconnected pin terminate "<<nodep<<endl);
|
||||||
|
AstVar* ucVarp = getCreateUnconnVarp(nodep);
|
||||||
|
nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp,
|
||||||
|
nodep->modVarp()->isOutput()));
|
||||||
|
// We don't need a driver on the wire; the lack of one will default to tristate
|
||||||
|
}
|
||||||
|
|
||||||
// Create the output enable pin, connect to new signal
|
// Create the output enable pin, connect to new signal
|
||||||
AstNode* enrefp;
|
AstNode* enrefp;
|
||||||
|
|
@ -524,14 +563,15 @@ class TristateVisitor : public TristateBaseVisitor {
|
||||||
outpinp->user2(true); // mark this visited
|
outpinp->user2(true); // mark this visited
|
||||||
m_cellp->addPinsp(outpinp);
|
m_cellp->addPinsp(outpinp);
|
||||||
// Simplify
|
// Simplify
|
||||||
outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, m_modp); // Note may change outpinp->exprp()
|
if (debug()>=9) outpinp->dumpTree(cout,"-pin-opr: ");
|
||||||
|
outAssignp = V3Inst::pinReconnectSimple(outpinp, m_cellp, m_modp, true); // Note may change outpinp->exprp()
|
||||||
if (debug()>=9) outpinp->dumpTree(cout,"-pin-out: ");
|
if (debug()>=9) outpinp->dumpTree(cout,"-pin-out: ");
|
||||||
if (debug()>=9 && outAssignp) outAssignp->dumpTree(cout,"-pin-out: ");
|
if (debug()>=9 && outAssignp) outAssignp->dumpTree(cout,"-pin-out: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existing pin becomes an input
|
// Existing pin becomes an input
|
||||||
TristateInPinVisitor visitor (nodep->exprp());
|
TristateInPinVisitor visitor (nodep->exprp());
|
||||||
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp); // Note may change nodep->exprp()
|
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true); // Note may change nodep->exprp()
|
||||||
if (debug()>=9) nodep->dumpTree(cout,"-pin-in: ");
|
if (debug()>=9) nodep->dumpTree(cout,"-pin-in: ");
|
||||||
|
|
||||||
// Connect enable to output signal
|
// Connect enable to output signal
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// DESCRIPTION: Verilator: Verilog Test module
|
|
||||||
//
|
|
||||||
// This file ONLY is placed into the Public Domain, for any use,
|
|
||||||
// without warranty, 2012 by Wilson Snyder.
|
|
||||||
|
|
||||||
module t (/*AUTOARG*/
|
|
||||||
// Inputs
|
|
||||||
clk
|
|
||||||
);
|
|
||||||
input clk;
|
|
||||||
|
|
||||||
t_tri4 t_tri4 (.t4(1'b0));
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module t_tri4 (/*AUTOARG*/
|
|
||||||
// Inputs
|
|
||||||
t4
|
|
||||||
);
|
|
||||||
input t4;
|
|
||||||
tri0 t4;
|
|
||||||
initial if (t4 !== 1'b0) $stop;
|
|
||||||
endmodule
|
|
||||||
|
|
@ -8,13 +8,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
fails=>$Self->{v3},
|
);
|
||||||
expect=>
|
|
||||||
qr{%Error: t/t_tri_pin0_bad.v:\d+: Unsupported tristate port expression: CONST '1'h0'
|
execute (
|
||||||
%Error: t/t_tri_pin0_bad.v:\d+: Output port is connected to a constant pin, electrical short
|
check_finished=>1,
|
||||||
%Error: Exiting due to},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2012 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
|
||||||
|
wire one = '1;
|
||||||
|
wire z0 = 'z;
|
||||||
|
wire z1 = 'z;
|
||||||
|
wire z2 = 'z;
|
||||||
|
wire z3 = 'z;
|
||||||
|
|
||||||
|
// verilator lint_off PINMISSING
|
||||||
|
t_tri0 tri0a (); // Error/warning
|
||||||
|
t_tri0 tri0b (.tn());
|
||||||
|
t_tri0 tri0z (.tn(z0));
|
||||||
|
t_tri0 #(.EXPECT(1'b0)) tri0c (.tn(1'b0));
|
||||||
|
t_tri0 #(.EXPECT(1'b1)) tri0d (.tn(1'b1)); // Warning would be reasonable given tri0 connect
|
||||||
|
t_tri0 #(.EXPECT(1'b0)) tri0e (.tn(~one));
|
||||||
|
t_tri0 #(.EXPECT(1'b1)) tri0f (.tn(one));
|
||||||
|
|
||||||
|
t_tri1 tri1a ();
|
||||||
|
t_tri1 tri1b (.tn());
|
||||||
|
t_tri1 tri1z (.tn(z1));
|
||||||
|
t_tri1 #(.EXPECT(1'b0)) tri1c (.tn(1'b0)); // Warning would be reasonable given tri1 connect
|
||||||
|
t_tri1 #(.EXPECT(1'b1)) tri1d (.tn(1'b1));
|
||||||
|
t_tri1 #(.EXPECT(1'b0)) tri1e (.tn(~one));
|
||||||
|
t_tri1 #(.EXPECT(1'b1)) tri1f (.tn(one));
|
||||||
|
|
||||||
|
t_tri2 tri2a ();
|
||||||
|
t_tri2 tri2b (.tn());
|
||||||
|
t_tri2 tri2z (.tn(z2));
|
||||||
|
t_tri2 #(.EXPECT(1'b0)) tri2c (.tn(1'b0));
|
||||||
|
t_tri2 #(.EXPECT(1'b1)) tri2d (.tn(1'b1));
|
||||||
|
t_tri2 #(.EXPECT(1'b0)) tri2e (.tn(~one));
|
||||||
|
t_tri2 #(.EXPECT(1'b1)) tri2f (.tn(one));
|
||||||
|
|
||||||
|
t_tri3 tri3a ();
|
||||||
|
t_tri3 tri3b (.tn());
|
||||||
|
t_tri3 tri3z (.tn(z3));
|
||||||
|
t_tri3 #(.EXPECT(1'b0)) tri3c (.tn(1'b0));
|
||||||
|
t_tri3 #(.EXPECT(1'b1)) tri3d (.tn(1'b1));
|
||||||
|
t_tri3 #(.EXPECT(1'b0)) tri3e (.tn(~one));
|
||||||
|
t_tri3 #(.EXPECT(1'b1)) tri3f (.tn(one));
|
||||||
|
// verilator lint_on PINMISSING
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
if (cyc==99) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t_tri0
|
||||||
|
#(parameter EXPECT=1'b0)
|
||||||
|
(tn);
|
||||||
|
input tn; // Illegal to be inout; spec requires net connection to any inout
|
||||||
|
tri0 tn;
|
||||||
|
wire clk = t.clk;
|
||||||
|
always @(posedge clk) if (tn !== EXPECT) $stop;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t_tri1
|
||||||
|
#(parameter EXPECT=1'b1)
|
||||||
|
(tn);
|
||||||
|
input tn;
|
||||||
|
tri1 tn;
|
||||||
|
wire clk = t.clk;
|
||||||
|
always @(posedge clk) if (tn !== EXPECT) $stop;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t_tri2
|
||||||
|
#(parameter EXPECT=1'b0)
|
||||||
|
(tn);
|
||||||
|
input tn;
|
||||||
|
pulldown(tn);
|
||||||
|
wire clk = t.clk;
|
||||||
|
always @(posedge clk) if (tn !== EXPECT) $stop;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t_tri3
|
||||||
|
#(parameter EXPECT=1'b1)
|
||||||
|
(tn);
|
||||||
|
input tn;
|
||||||
|
pullup(tn);
|
||||||
|
wire clk = t.clk;
|
||||||
|
always @(posedge clk) if (tn !== EXPECT) $stop;
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue