Fix false LATCH warning on 'unique if' (#3088).
This commit is contained in:
parent
203993b018
commit
a57a3579c0
3
Changes
3
Changes
|
|
@ -25,7 +25,7 @@ Verilator 5.001 devel
|
||||||
* Introduce a new combinational logic optimizer (DFG), that can yield
|
* Introduce a new combinational logic optimizer (DFG), that can yield
|
||||||
significant performance improvements on some designs. [Geza Lore, Shunyao CAD]
|
significant performance improvements on some designs. [Geza Lore, Shunyao CAD]
|
||||||
* Add --binary option as alias of --main --exe --build --timing (#3625).
|
* Add --binary option as alias of --main --exe --build --timing (#3625).
|
||||||
For designs where C++ was only used to make a simple testbench we
|
For designs where C++ was only used to make a simple no-I/O testbench, we
|
||||||
recommend abandoning that C++, and instead letting Verilator build it
|
recommend abandoning that C++, and instead letting Verilator build it
|
||||||
with --binary (or --main).
|
with --binary (or --main).
|
||||||
|
|
||||||
|
|
@ -38,6 +38,7 @@ Verilator 5.001 devel
|
||||||
* Add --dump-tree-dot to enable dumping Ast Tree .dot files (#3636). [Marcel Chang]
|
* Add --dump-tree-dot to enable dumping Ast Tree .dot files (#3636). [Marcel Chang]
|
||||||
* Add --get-supported to determine what features are in Verilator.
|
* Add --get-supported to determine what features are in Verilator.
|
||||||
* Add error on real edge event control.
|
* Add error on real edge event control.
|
||||||
|
* Fix false LATCH warning on 'unique if' (#3088). [Rachit Nigam]
|
||||||
* Fix cell assigning integer array parameters (#3299). [Michael Platzer]
|
* Fix cell assigning integer array parameters (#3299). [Michael Platzer]
|
||||||
* Fix LSB error on --hierarchical submodules (#3539). [danbone]
|
* Fix LSB error on --hierarchical submodules (#3539). [danbone]
|
||||||
* Fix $display of fixed-width numbers (#3565). [Iztok Jeras]
|
* Fix $display of fixed-width numbers (#3565). [Iztok Jeras]
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ private:
|
||||||
// Add a internal if to check assertions are on.
|
// Add a internal if to check assertions are on.
|
||||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
AstNode* const newp = new AstIf{
|
AstNodeIf* const newp = new AstIf{
|
||||||
fl,
|
fl,
|
||||||
(force ? new AstConst{fl, AstConst::BitTrue{}}
|
(force ? new AstConst{fl, AstConst::BitTrue{}}
|
||||||
: // If assertions are off, have constant propagation rip them out later
|
: // If assertions are off, have constant propagation rip them out later
|
||||||
|
|
@ -108,6 +108,7 @@ private:
|
||||||
new AstCMath{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
|
new AstCMath{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
|
||||||
: static_cast<AstNode*>(new AstConst{fl, AstConst::BitFalse{}}))),
|
: static_cast<AstNode*>(new AstConst{fl, AstConst::BitFalse{}}))),
|
||||||
nodep};
|
nodep};
|
||||||
|
newp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
newp->user1(true); // Don't assert/cover this if
|
newp->user1(true); // Don't assert/cover this if
|
||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
|
|
@ -164,6 +165,7 @@ private:
|
||||||
|
|
||||||
if (bodysp && passsp) bodysp = bodysp->addNext(passsp);
|
if (bodysp && passsp) bodysp = bodysp->addNext(passsp);
|
||||||
ifp = new AstIf{nodep->fileline(), propp, bodysp};
|
ifp = new AstIf{nodep->fileline(), propp, bodysp};
|
||||||
|
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
bodysp = ifp;
|
bodysp = ifp;
|
||||||
} else if (VN_IS(nodep, Assert) || VN_IS(nodep, AssertIntrinsic)) {
|
} else if (VN_IS(nodep, Assert) || VN_IS(nodep, AssertIntrinsic)) {
|
||||||
if (nodep->immediate()) {
|
if (nodep->immediate()) {
|
||||||
|
|
@ -176,6 +178,7 @@ private:
|
||||||
if (failsp) failsp = newIfAssertOn(failsp, force);
|
if (failsp) failsp = newIfAssertOn(failsp, force);
|
||||||
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||||
ifp = new AstIf{nodep->fileline(), propp, passsp, failsp};
|
ifp = new AstIf{nodep->fileline(), propp, passsp, failsp};
|
||||||
|
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
// It's more LIKELY that we'll take the nullptr if clause
|
// It's more LIKELY that we'll take the nullptr if clause
|
||||||
// than the sim-killing else clause:
|
// than the sim-killing else clause:
|
||||||
ifp->branchPred(VBranchPred::BP_LIKELY);
|
ifp->branchPred(VBranchPred::BP_LIKELY);
|
||||||
|
|
@ -253,6 +256,7 @@ private:
|
||||||
AstIf* const checkifp
|
AstIf* const checkifp
|
||||||
= new AstIf{nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
|
= new AstIf{nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
|
||||||
newFireAssert(nodep, "'unique if' statement violated"), newifp};
|
newFireAssert(nodep, "'unique if' statement violated"), newifp};
|
||||||
|
checkifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
|
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||||
nodep->replaceWith(checkifp);
|
nodep->replaceWith(checkifp);
|
||||||
pushDeletep(nodep);
|
pushDeletep(nodep);
|
||||||
|
|
@ -323,6 +327,7 @@ private:
|
||||||
nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
|
nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
|
||||||
newFireAssert(nodep,
|
newFireAssert(nodep,
|
||||||
"synthesis parallel_case, but multiple matches found")};
|
"synthesis parallel_case, but multiple matches found")};
|
||||||
|
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||||
nodep->addNotParallelp(ifp);
|
nodep->addNotParallelp(ifp);
|
||||||
}
|
}
|
||||||
|
|
@ -425,6 +430,7 @@ private:
|
||||||
new AstEq{fl, new AstConst{fl, monNum},
|
new AstEq{fl, new AstConst{fl, monNum},
|
||||||
newMonitorNumVarRefp(nodep, VAccess::READ)}},
|
newMonitorNumVarRefp(nodep, VAccess::READ)}},
|
||||||
stmtsp};
|
stmtsp};
|
||||||
|
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||||
AstNode* const newp = new AstAlways{fl, VAlwaysKwd::ALWAYS, nullptr, ifp};
|
AstNode* const newp = new AstAlways{fl, VAlwaysKwd::ALWAYS, nullptr, ifp};
|
||||||
m_modp->addStmtsp(newp);
|
m_modp->addStmtsp(newp);
|
||||||
|
|
@ -443,6 +449,7 @@ private:
|
||||||
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
|
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
|
||||||
AstNode* const stmtsp = nodep;
|
AstNode* const stmtsp = nodep;
|
||||||
AstIf* const ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp};
|
AstIf* const ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp};
|
||||||
|
ifp->isBoundsCheck(true); // To avoid LATCH warning
|
||||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||||
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
|
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
|
||||||
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
||||||
|
|
|
||||||
|
|
@ -504,7 +504,7 @@ class AstNodeIf VL_NOT_FINAL : public AstNodeStmt {
|
||||||
// @astgen op3 := elsesp : List[AstNode]
|
// @astgen op3 := elsesp : List[AstNode]
|
||||||
private:
|
private:
|
||||||
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
|
VBranchPred m_branchPred; // Branch prediction as taken/untaken?
|
||||||
bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking
|
bool m_isBoundsCheck; // True if this if node is for assertion/bounds checking
|
||||||
protected:
|
protected:
|
||||||
AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* thensp, AstNode* elsesp)
|
AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* thensp, AstNode* elsesp)
|
||||||
: AstNodeStmt{t, fl} {
|
: AstNodeStmt{t, fl} {
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,27 @@ module test (
|
||||||
input [2:0] a,
|
input [2:0] a,
|
||||||
input [3:0] c,
|
input [3:0] c,
|
||||||
|
|
||||||
output reg [7:0] b
|
output reg [7:0] o1,
|
||||||
|
output reg [7:0] o2
|
||||||
);
|
);
|
||||||
|
|
||||||
integer i;
|
integer i;
|
||||||
|
|
||||||
always @ (*)
|
always @ (*) begin
|
||||||
begin
|
case(a)
|
||||||
case(a)
|
{3'b000}: o1 = 8'd1;
|
||||||
{3'b000}: b = 8'd1;
|
{3'b001}:
|
||||||
{3'b001}:
|
for(i=0;i<4;i=i+1) o1[i*2+:2] = 2'(c[i]);
|
||||||
for(i=0;i<4;i=i+1) b[i*2+:2] = 2'(c[i]);
|
{3'b010}: o1 = 8'd3;
|
||||||
{3'b010}: b = 8'd3;
|
{3'b011}: o1 = 8'd4;
|
||||||
{3'b011}: b = 8'd4;
|
default : o1 = 0;
|
||||||
default : b = 0;
|
endcase
|
||||||
endcase
|
end
|
||||||
end
|
|
||||||
|
always_comb begin
|
||||||
|
unique if (a[0]) o2 = 1;
|
||||||
|
else if (a[1]) o2 = 2;
|
||||||
|
else o2 = 3;
|
||||||
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue