Add SYNCASYNCNET
This commit is contained in:
parent
4ca7f8834c
commit
8d21917035
2
Changes
2
Changes
|
|
@ -26,6 +26,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
*** With --Wall, add INCABSPATH warning on `include with absolute paths.
|
||||
|
||||
*** With --Wall, add SYNCASYNCNET warning on mixed sync/async reset nets.
|
||||
|
||||
*** With --Wall, add UNDRIVEN warning on undriven nets.
|
||||
|
||||
*** With --Wall, add UNUSED warning on unused nets.
|
||||
|
|
|
|||
|
|
@ -872,9 +872,9 @@ Disable the specified warning message.
|
|||
|
||||
Disable all lint related warning messages, and all style warnings. This is
|
||||
equivalent to "-Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX
|
||||
-Wno-CASEWITHX -Wno-CMPCONST -Wno-IMPLICIT -Wno-LITENDIAN -Wno-UNDRIVEN
|
||||
-Wno-UNSIGNED -Wno-UNUSED -Wno-WIDTH" plus the list shown
|
||||
for Wno-style.
|
||||
-Wno-CASEWITHX -Wno-CMPCONST -Wno-IMPLICIT -Wno-LITENDIAN -Wno-SYNCASYNCNET
|
||||
-Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED -Wno-WIDTH" plus the list shown for
|
||||
Wno-style.
|
||||
|
||||
It is strongly recommended you cleanup your code rather than using this
|
||||
option, it is only intended to be use when running test-cases of code
|
||||
|
|
@ -884,7 +884,8 @@ received from third parties.
|
|||
|
||||
Disable all code style related warning messages (note by default they are
|
||||
already disabled). This is equivalent to "-Wno-DECLFILENAME -Wno-DEFPARAM
|
||||
-Wno-INCABSPATH -Wno-UNDRIVEN -Wno-UNUSED -Wno-VARHIDDEN".
|
||||
-Wno-INCABSPATH -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNUSED
|
||||
-Wno-VARHIDDEN".
|
||||
|
||||
=item -Wwarn-I<message>
|
||||
|
||||
|
|
@ -895,14 +896,14 @@ Enables the specified warning message.
|
|||
Enable all lint related warning messages (note by default they are already
|
||||
enabled), but do not affect style messages. This is equivalent to
|
||||
"-Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASEWITHX
|
||||
-Wwarn-CMPCONST -Wwarn-IMPLICIT -Wwarn-LITENDIAN -Wwarn-UNDRIVEN
|
||||
-Wwarn-UNSIGNED -Wwarn-UNUSED -Wwarn-WIDTH".
|
||||
-Wwarn-CMPCONST -Wwarn-IMPLICIT -Wwarn-LITENDIAN -Wwarn-UNSIGNED
|
||||
-Wwarn-WIDTH".
|
||||
|
||||
=item -Wwarn-style
|
||||
|
||||
Enable all code style related warning messages. This is equivalent to
|
||||
"-Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH -Wwarn-UNDRIVEN
|
||||
-Wwarn-UNUSED -Wwarn-VARHIDDEN".
|
||||
"-Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH -Wwarn-SYNCASYNCNET
|
||||
-Wwarn-UNDRIVEN -Wwarn-UNUSED -Wwarn-VARHIDDEN".
|
||||
|
||||
=item -x-assign 0
|
||||
|
||||
|
|
@ -2565,6 +2566,18 @@ name would result in odd C compiler errors. You may disable this error
|
|||
message as you would disable warnings, but the symbol will be renamed by
|
||||
Verilator to avoid the conflict.
|
||||
|
||||
=item SYNCASYNCNET
|
||||
|
||||
Warns that the specified net is used in at least two different always
|
||||
statements with posedge/negedges (i.e. a flop). One usage has the signal
|
||||
in the sensitivity list and body, probably as a async reset, and the other
|
||||
usage has the signal only in the body, probably as a sync reset. Mixing
|
||||
sync and async resets is usually a mistake. The warning may be disabled
|
||||
with a lint_off pragma around the net, or either flopped block.
|
||||
|
||||
Disabled by default as this is a code style warning; it will simulate
|
||||
correctly.
|
||||
|
||||
=item TASKNSVAR
|
||||
|
||||
Error when a call to a task or function has a output from that task tied to
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ public:
|
|||
REDEFMACRO, // Redefining existing define macro
|
||||
STMTDLY, // Delayed statement
|
||||
SYMRSVDWORD, // Symbol is Reserved Word
|
||||
SYNCASYNCNET, // Mixed sync + async reset
|
||||
UNDRIVEN, // No drivers
|
||||
UNOPT, // Unoptimizable block
|
||||
UNOPTFLAT, // Unoptimizable block after flattening
|
||||
|
|
@ -109,7 +110,7 @@ public:
|
|||
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPURE", "INCABSPATH",
|
||||
"LITENDIAN", "MODDUP",
|
||||
"MULTIDRIVEN", "REDEFMACRO",
|
||||
"STMTDLY", "SYMRSVDWORD",
|
||||
"STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
||||
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
|
||||
" MAX"
|
||||
|
|
@ -138,6 +139,7 @@ public:
|
|||
bool styleError() const { return ( m_e==DEFPARAM
|
||||
|| m_e==DECLFILENAME
|
||||
|| m_e==INCABSPATH
|
||||
|| m_e==SYNCASYNCNET
|
||||
|| m_e==UNDRIVEN
|
||||
|| m_e==UNUSED
|
||||
|| m_e==VARHIDDEN ); }
|
||||
|
|
|
|||
|
|
@ -86,19 +86,25 @@ class GateVarVertex : public GateEitherVertex {
|
|||
AstVarScope* m_varScp;
|
||||
bool m_isTop;
|
||||
bool m_isClock;
|
||||
AstNode* m_rstSyncNodep; // Used as reset and not in SenItem, in clocked always
|
||||
AstNode* m_rstAsyncNodep; // Used as reset and in SenItem, in clocked always
|
||||
public:
|
||||
GateVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: GateEitherVertex(graphp, scopep), m_varScp(varScp), m_isTop(false)
|
||||
, m_isClock(false) {}
|
||||
, m_isClock(false), m_rstSyncNodep(NULL), m_rstAsyncNodep(NULL) {}
|
||||
virtual ~GateVarVertex() {}
|
||||
// Accessors
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const { return (cvtToStr((void*)m_varScp)+" "+varScp()->name()); }
|
||||
virtual string dotColor() const { return "blue"; }
|
||||
void setIsTop() { m_isTop = true; }
|
||||
void setIsClock() { m_isClock = true; setConsumed("isclk"); }
|
||||
bool isTop() const { return m_isTop; }
|
||||
void setIsTop() { m_isTop = true; }
|
||||
bool isClock() const { return m_isClock; }
|
||||
void setIsClock() { m_isClock = true; setConsumed("isclk"); }
|
||||
AstNode* rstSyncNodep() const { return m_rstSyncNodep; }
|
||||
void rstSyncNodep(AstNode* nodep) { m_rstSyncNodep=nodep; }
|
||||
AstNode* rstAsyncNodep() const { return m_rstAsyncNodep; }
|
||||
void rstAsyncNodep(AstNode* nodep) { m_rstAsyncNodep=nodep; }
|
||||
};
|
||||
|
||||
class GateLogicVertex : public GateEitherVertex {
|
||||
|
|
@ -236,7 +242,10 @@ private:
|
|||
//Entire netlist:
|
||||
// AstVarScope::user1p -> GateVarVertex* for usage var, 0=not set yet
|
||||
// {statement}Node::user1p -> GateLogicVertex* for this statement
|
||||
// AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement
|
||||
// AstVar::user2 -> bool: Warned about SYNCASYNCNET
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
|
|
@ -286,12 +295,12 @@ private:
|
|||
}
|
||||
if (varscp->varp()->isUsedClock()) vertexp->setConsumed("clock");
|
||||
}
|
||||
if (m_inSenItem) vertexp->setIsClock();
|
||||
return vertexp;
|
||||
}
|
||||
|
||||
void optimizeSignals(bool allowMultiIn);
|
||||
void optimizeElimVar(AstVarScope* varscp, AstNode* logicp, AstNode* consumerp);
|
||||
void warnSignals();
|
||||
void consumedMark();
|
||||
void consumedMarkRecurse(GateEitherVertex* vertexp);
|
||||
void consumedMove();
|
||||
|
|
@ -310,6 +319,8 @@ private:
|
|||
optimizeSignals(false);
|
||||
// Then propagate more complicated equations
|
||||
optimizeSignals(true);
|
||||
// Warn
|
||||
warnSignals();
|
||||
consumedMark();
|
||||
m_graph.dumpDotFilePrefixed("gate_opt");
|
||||
// Rewrite assignments
|
||||
|
|
@ -334,7 +345,9 @@ private:
|
|||
UINFO(4," BLOCK "<<nodep<<endl);
|
||||
m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible
|
||||
m_activep = nodep;
|
||||
AstNode::user2ClearTree();
|
||||
nodep->iterateChildren(*this);
|
||||
AstNode::user2ClearTree();
|
||||
m_activep = NULL;
|
||||
m_activeReducible = true;
|
||||
}
|
||||
|
|
@ -343,14 +356,24 @@ private:
|
|||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
GateVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
GateVarVertex* vvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
if (m_inSenItem) vvertexp->setIsClock();
|
||||
// For SYNCASYNCNET
|
||||
if (m_inSenItem) varscp->user2(true);
|
||||
else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) {
|
||||
if (varscp->user2()) {
|
||||
if (!vvertexp->rstSyncNodep()) vvertexp->rstSyncNodep(nodep);
|
||||
} else {
|
||||
if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep);
|
||||
}
|
||||
}
|
||||
// We use weight of one; if we ref the var more than once, when we simplify,
|
||||
// the weight will increase
|
||||
if (nodep->lvalue()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1);
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
|
||||
new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -449,7 +472,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
|||
if (0) {
|
||||
// If we warned here after constant propagation, what the user considered
|
||||
// reasonable logic may have disappeared. Issuing a warning would
|
||||
// thus be confusing.
|
||||
// thus be confusing. V3Undriven now handles this.
|
||||
vvertexp->varScp()->varp()->v3warn(UNDRIVEN,"Signal has no drivers "
|
||||
<<vvertexp->scopep()->prettyName()<<"."
|
||||
<<vvertexp->varScp()->varp()->prettyName());
|
||||
|
|
@ -643,6 +666,34 @@ void GateVisitor::consumedMove() {
|
|||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void GateVisitor::warnSignals() {
|
||||
AstNode::user2ClearTree();
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
AstVarScope* vscp = vvertexp->varScp();
|
||||
AstNode* sp = vvertexp->rstSyncNodep();
|
||||
AstNode* ap = vvertexp->rstAsyncNodep();
|
||||
if (ap && sp && !vscp->varp()->user2()) {
|
||||
// This is somewhat wrong, as marking one flop as ok for sync
|
||||
// may mean a different flop now fails. However it's a pain to
|
||||
// then report a warning in a new place - we should report them all at once.
|
||||
// Instead we'll disable if any disabled
|
||||
if (!vscp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
|
||||
&& !ap->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
|
||||
&& !sp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
|
||||
) {
|
||||
vscp->varp()->user2(true); // Warn only once per signal
|
||||
vscp->v3warn(SYNCASYNCNET,"Signal flopped as both synchronous and async: "<<vscp->prettyName());
|
||||
ap->v3warn(SYNCASYNCNET,"... Location of async usage");
|
||||
sp->v3warn(SYNCASYNCNET,"... Location of sync usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Push constant into expressions and reevaluate
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2008 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 (
|
||||
v_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME --if-depth 10"],
|
||||
fails=>1,
|
||||
verilator_make_gcc => 0,
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
expect=>
|
||||
'%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:\d+: Signal flopped as both synchronous and async: TOP->rst_both_l
|
||||
%Warning-SYNCASYNCNET: Use .* around source to disable this message.
|
||||
%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:\d+: ... Location of async usage
|
||||
%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:\d+: ... Location of sync usage
|
||||
%Error: Exiting due to.*',
|
||||
) if $Self->{v3};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2010 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
rst_sync_l, rst_both_l, rst_async_l, d, clk
|
||||
);
|
||||
/*AUTOINPUT*/
|
||||
// Beginning of automatic inputs (from unused autoinst inputs)
|
||||
input clk; // To sub1 of sub1.v, ...
|
||||
input d; // To sub1 of sub1.v, ...
|
||||
input rst_async_l; // To sub2 of sub2.v
|
||||
input rst_both_l; // To sub1 of sub1.v, ...
|
||||
input rst_sync_l; // To sub1 of sub1.v
|
||||
// End of automatics
|
||||
|
||||
sub1 sub1 (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.rst_both_l (rst_both_l),
|
||||
.rst_sync_l (rst_sync_l),
|
||||
.d (d));
|
||||
sub2 sub2 (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.rst_both_l (rst_both_l),
|
||||
.rst_async_l (rst_async_l),
|
||||
.d (d));
|
||||
endmodule
|
||||
|
||||
module sub1 (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk, rst_both_l, rst_sync_l, d
|
||||
);
|
||||
|
||||
input clk;
|
||||
input rst_both_l;
|
||||
input rst_sync_l;
|
||||
//input rst_async_l;
|
||||
input d;
|
||||
reg q1;
|
||||
reg q2;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (~rst_sync_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
q1 <= 1'h0;
|
||||
// End of automatics
|
||||
end else begin
|
||||
q1 <= d;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
q2 <= (~rst_both_l) ? 1'b0 : d;
|
||||
if (0 && q1 && q2) ;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module sub2 (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk, rst_both_l, rst_async_l, d
|
||||
);
|
||||
|
||||
input clk;
|
||||
input rst_both_l;
|
||||
//input rst_sync_l;
|
||||
input rst_async_l;
|
||||
input d;
|
||||
reg q1;
|
||||
reg q2;
|
||||
reg q3;
|
||||
|
||||
always @(posedge clk or negedge rst_async_l) begin
|
||||
if (~rst_async_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
q1 <= 1'h0;
|
||||
// End of automatics
|
||||
end else begin
|
||||
q1 <= d;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_both_l) begin
|
||||
q2 <= (~rst_both_l) ? 1'b0 : d;
|
||||
end
|
||||
// Make there be more async uses than sync uses
|
||||
always @(posedge clk or negedge rst_both_l) begin
|
||||
q3 <= (~rst_both_l) ? 1'b0 : d;
|
||||
if (0 && q1 && q2 && q3) ;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue