Add checks that verify an always statement has delay.
This patch adds check to determine if an always block has delay in it or not. If there is no delay a runtime infinite loop will occur. For the indeterminate case it will print a warning message if the new -Winfloop flag is given. This flag is not part of the -Wall check!
This commit is contained in:
parent
7b705a0212
commit
c38e8182c2
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __compiler_H
|
||||
#define __compiler_H
|
||||
/*
|
||||
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -76,6 +76,9 @@ extern bool warn_timescale;
|
|||
/* Warn about legal but questionable module port bindings. */
|
||||
extern bool warn_portbinding;
|
||||
|
||||
/* Warn about structures that may have infinite loops. */
|
||||
extern bool warn_inf_loop;
|
||||
|
||||
/* This is true if verbose output is requested. */
|
||||
extern bool verbose_flag;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.8
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.TH iverilog 1 "$Date: 2007/06/05 01:56:12 $" Version "$Date: 2007/06/05 01:56:12 $"
|
||||
.TH iverilog 1 "April 22nd, 2008" Version "0.9.devel"
|
||||
.SH NAME
|
||||
iverilog - Icarus Verilog compiler
|
||||
|
||||
|
|
@ -251,6 +251,21 @@ inherit timescale from another file. Both probably mean that
|
|||
timescales are inconsistent, and simulation timing can be confusing
|
||||
and dependent on compilation order.
|
||||
|
||||
.TP 8
|
||||
.B infloop
|
||||
This enables warnings for \fRalways\fP statements that may have runtime
|
||||
infinite loops (has paths with no or zero delay). This class of warnings
|
||||
is not included in \fB-Wall\fP and hence does not have a \fBno-\fP variant.
|
||||
A fatal error message will always be printed when the compiler can
|
||||
determine that there will definitely be an infinite loop (all paths have
|
||||
no or zero delay).
|
||||
|
||||
When you suspect an always statement is producing a runtime infinite loop
|
||||
use this flag to find the always statements that need to have their logic
|
||||
verified. It is expected that many of the warnings will be false
|
||||
positives, since the code treats the value of all variables and signals
|
||||
as indeterminate.
|
||||
|
||||
.SH "SYSTEM FUNCTION TABLE FILES"
|
||||
If the source file name as a \fB.sft\fP suffix, then it is taken to be
|
||||
a system function table file. A System function table file is used to
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -358,6 +358,11 @@ static void process_warning_switch(const char*name)
|
|||
} else if (strcmp(name,"timescale") == 0) {
|
||||
if (! strchr(warning_flags, 't'))
|
||||
strcat(warning_flags, "t");
|
||||
/* Since the infinite loop check is not part of 'all' it
|
||||
* does not have a no- version. */
|
||||
} else if (strcmp(name,"infloop") == 0) {
|
||||
if (! strchr(warning_flags, 'l'))
|
||||
strcat(warning_flags, "l");
|
||||
} else if (strcmp(name,"no-implicit") == 0) {
|
||||
char*cp = strchr(warning_flags, 'i');
|
||||
if (cp) while (*cp) {
|
||||
|
|
@ -703,7 +708,7 @@ int main(int argc, char **argv)
|
|||
|
||||
if (version_flag || verbose_flag) {
|
||||
printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n");
|
||||
printf("Copyright 1998-2007 Stephen Williams\n");
|
||||
printf("Copyright 1998-2008 Stephen Williams\n");
|
||||
puts(NOTICE);
|
||||
|
||||
if (version_flag)
|
||||
|
|
@ -841,4 +846,3 @@ int main(int argc, char **argv)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
23
elaborate.cc
23
elaborate.cc
|
|
@ -3277,6 +3277,29 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
|
|||
verinum(1));
|
||||
} while (0);
|
||||
|
||||
/* If this is an always block and we have no or zero delay then
|
||||
* a runtime infinite loop will happen. If we possible have some
|
||||
* delay then print a warning that an infinite loop is possible.
|
||||
*/
|
||||
if (type() == PProcess::PR_ALWAYS) {
|
||||
DelayType dly_type = top->statement()->delay_type();
|
||||
|
||||
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {
|
||||
cerr << get_fileline() << ": error: always statement"
|
||||
<< " does not have any delay." << endl;
|
||||
cerr << get_fileline() << ": : A runtime infinite"
|
||||
<< " loop will occur." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
|
||||
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
|
||||
cerr << get_fileline() << ": warning: always statement"
|
||||
<< " may not have any delay." << endl;
|
||||
cerr << get_fileline() << ": : A runtime infinite"
|
||||
<< " loop may be possible." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
109
main.cc
109
main.cc
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
const char COPYRIGHT[] =
|
||||
"Copyright (c) 1998-2005 Stephen Williams (steve@icarus.com)";
|
||||
"Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com)";
|
||||
|
||||
/*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -18,9 +18,6 @@ const char COPYRIGHT[] =
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: main.cc,v 1.95 2007/04/19 02:52:53 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
||||
|
|
@ -113,6 +110,7 @@ FILE *depend_file = NULL;
|
|||
bool warn_implicit = false;
|
||||
bool warn_timescale = false;
|
||||
bool warn_portbinding = false;
|
||||
bool warn_inf_loop = false;
|
||||
|
||||
bool error_implicit = false;
|
||||
|
||||
|
|
@ -434,6 +432,9 @@ static void read_iconfig_file(const char*ipath)
|
|||
case 'i':
|
||||
warn_implicit = true;
|
||||
break;
|
||||
case 'l':
|
||||
warn_inf_loop = true;
|
||||
break;
|
||||
case 'p':
|
||||
warn_portbinding = true;
|
||||
break;
|
||||
|
|
@ -830,103 +831,3 @@ int main(int argc, char*argv[])
|
|||
|
||||
return des? des->errors : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: main.cc,v $
|
||||
* Revision 1.95 2007/04/19 02:52:53 steve
|
||||
* Add support for -v flag in command file.
|
||||
*
|
||||
* Revision 1.94 2007/03/07 04:24:59 steve
|
||||
* Make integer width controllable.
|
||||
*
|
||||
* Revision 1.93 2006/09/28 04:35:18 steve
|
||||
* Support selective control of specify and xtypes features.
|
||||
*
|
||||
* Revision 1.92 2005/07/14 23:38:43 steve
|
||||
* Display as version 0.9.devel
|
||||
*
|
||||
* Revision 1.91 2005/07/07 16:22:49 steve
|
||||
* Generalize signals to carry types.
|
||||
*
|
||||
* Revision 1.90 2005/06/28 04:25:55 steve
|
||||
* Remove reference to SystemVerilog.
|
||||
*
|
||||
* Revision 1.89 2005/04/24 23:44:02 steve
|
||||
* Update DFF support to new data flow.
|
||||
*
|
||||
* Revision 1.88 2005/01/22 01:06:55 steve
|
||||
* Change case compare from logic to an LPM node.
|
||||
*
|
||||
* Revision 1.87 2004/12/11 02:31:26 steve
|
||||
* Rework of internals to carry vectors through nexus instead
|
||||
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
||||
* down this path.
|
||||
*
|
||||
* Revision 1.86 2004/10/04 01:10:53 steve
|
||||
* Clean up spurious trailing white space.
|
||||
*
|
||||
* Revision 1.85 2004/09/25 01:58:44 steve
|
||||
* Add a debug_elaborate flag
|
||||
*
|
||||
* Revision 1.84 2004/09/10 23:51:42 steve
|
||||
* Fix the evaluation of constant ternary expressions.
|
||||
*
|
||||
* Revision 1.83 2004/09/05 17:44:42 steve
|
||||
* Add support for module instance arrays.
|
||||
*
|
||||
* Revision 1.82 2004/03/10 04:51:24 steve
|
||||
* Add support for system function table files.
|
||||
*
|
||||
* Revision 1.81 2004/02/18 17:11:56 steve
|
||||
* Use perm_strings for named langiage items.
|
||||
*
|
||||
* Revision 1.80 2004/02/15 00:19:29 steve
|
||||
* Report elaboration errors without crashing.
|
||||
*
|
||||
* Revision 1.79 2003/11/26 01:37:14 steve
|
||||
* Properly initialize vpi_module_list with system.
|
||||
*
|
||||
* Revision 1.78 2003/11/13 05:55:33 steve
|
||||
* Move the DLL= flag to target config files.
|
||||
*
|
||||
* Revision 1.77 2003/11/13 04:09:49 steve
|
||||
* Pass flags through the temporary config file.
|
||||
*
|
||||
* Revision 1.76 2003/11/13 03:10:38 steve
|
||||
* ivl -F and -t flags are onpassed throught the -C file.
|
||||
*
|
||||
* Revision 1.75 2003/11/10 20:59:03 steve
|
||||
* Design::get_flag returns const char* instead of string.
|
||||
*
|
||||
* Revision 1.74 2003/11/01 04:22:30 steve
|
||||
* Accept functors in the config file.
|
||||
*
|
||||
* Revision 1.73 2003/10/26 22:43:42 steve
|
||||
* Improve -V messages,
|
||||
*
|
||||
* Revision 1.72 2003/09/26 02:17:14 steve
|
||||
* Delete pform when done with it.
|
||||
*
|
||||
* Revision 1.71 2003/09/25 00:25:14 steve
|
||||
* Summary list of missing modules.
|
||||
*
|
||||
* Revision 1.70 2003/09/23 05:57:36 steve
|
||||
* Pass -m flag from driver via iconfig file.
|
||||
*
|
||||
* Revision 1.69 2003/09/22 01:12:08 steve
|
||||
* Pass more ivl arguments through the iconfig file.
|
||||
*
|
||||
* Revision 1.68 2003/06/20 00:53:19 steve
|
||||
* Module attributes from the parser
|
||||
* through to elaborated form.
|
||||
*
|
||||
* Revision 1.67 2003/04/24 05:25:27 steve
|
||||
* Dump design even on errors.
|
||||
*
|
||||
* Revision 1.66 2003/03/01 06:25:30 steve
|
||||
* Add the lex_strings string handler, and put
|
||||
* scope names and system task/function names
|
||||
* into this table. Also, permallocate event
|
||||
* names from the beginning.
|
||||
*/
|
||||
|
||||
|
|
|
|||
204
netlist.cc
204
netlist.cc
|
|
@ -2417,3 +2417,207 @@ const NetProc*NetTaskDef::proc() const
|
|||
{
|
||||
return proc_;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the delay_type() functions. They are used to determine
|
||||
* the type of delay for the given object.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function implements the following table:
|
||||
*
|
||||
* in_A in_B out
|
||||
* NO NO NO
|
||||
* NO ZERO ZERO
|
||||
* NO POS POS
|
||||
* NO DEF POS
|
||||
* ZERO NO ZERO
|
||||
* ZERO ZERO ZERO
|
||||
* ZERO POS POS
|
||||
* ZERO DEF POS
|
||||
* POS NO POS
|
||||
* POS ZERO POS
|
||||
* POS POS POS
|
||||
* POS DEF POS
|
||||
* DEF NO POS
|
||||
* DEF ZERO POS
|
||||
* DEF POS POS
|
||||
* DEF DEF DEF
|
||||
*
|
||||
* It is used to combine two delay values.
|
||||
*/
|
||||
static DelayType combine_delays(const DelayType a, const DelayType b)
|
||||
{
|
||||
/* The default is POSSIBLE_DELAY. */
|
||||
DelayType result = POSSIBLE_DELAY;
|
||||
|
||||
/* If both are no or zero delay then we return ZERO_DELAY. */
|
||||
if ((a == NO_DELAY || a == ZERO_DELAY) &&
|
||||
(b == NO_DELAY || b == ZERO_DELAY)) {
|
||||
result = ZERO_DELAY;
|
||||
}
|
||||
|
||||
/* Except if both are no delay then we return NO_DELAY. */
|
||||
if (a == NO_DELAY && b == NO_DELAY) {
|
||||
result = NO_DELAY;
|
||||
}
|
||||
|
||||
/* If both are definite delay then we return DEFINITE_DELAY. */
|
||||
if (a == DEFINITE_DELAY && b == DEFINITE_DELAY) {
|
||||
result = DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to see what we can find out about the delay when it
|
||||
* is given as an expression. We also use this for loop expressions.
|
||||
*/
|
||||
static DelayType delay_type_from_expr(const NetExpr*expr)
|
||||
{
|
||||
DelayType result = POSSIBLE_DELAY;
|
||||
|
||||
if (const NetEConst*e = dynamic_cast<const NetEConst*>(expr)) {
|
||||
if (e->value().is_zero()) result = ZERO_DELAY;
|
||||
else result = DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
if (const NetECReal*e = dynamic_cast<const NetECReal*>(expr)) {
|
||||
if (e->value().as_double() == 0.0) result = ZERO_DELAY;
|
||||
else result = DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The looping structures can use the same basic code so put it here
|
||||
* instead of duplicating it for each one (repeat and while).
|
||||
*/
|
||||
static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc)
|
||||
{
|
||||
DelayType result;
|
||||
|
||||
switch (delay_type_from_expr(expr)) {
|
||||
/* We have a constant false expression so the body never runs. */
|
||||
case ZERO_DELAY:
|
||||
result = NO_DELAY;
|
||||
break;
|
||||
/* We have a constant true expression so the body always runs. */
|
||||
case DEFINITE_DELAY:
|
||||
result = proc->delay_type();
|
||||
break;
|
||||
/* We don't know if the body will run so reduce a DEFINITE_DELAY
|
||||
* to a POSSIBLE_DELAY. All other stay the same. */
|
||||
case POSSIBLE_DELAY:
|
||||
result = combine_delays(NO_DELAY, proc->delay_type());
|
||||
break;
|
||||
/* This should never happen since delay_type_from_expr() only
|
||||
* returns three different values. */
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* The default object does not have any delay. */
|
||||
DelayType NetProc::delay_type() const
|
||||
{
|
||||
return NO_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetBlock::delay_type() const
|
||||
{
|
||||
DelayType result = NO_DELAY;
|
||||
|
||||
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
|
||||
DelayType dt = cur->delay_type();
|
||||
if (dt > result) result = dt;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetCase::delay_type() const
|
||||
{
|
||||
DelayType result = NO_DELAY;
|
||||
bool def_stmt = false;
|
||||
unsigned nstmts = nitems();
|
||||
|
||||
for (unsigned idx = 0; idx < nstmts; idx += 1) {
|
||||
if (!expr(idx)) def_stmt = true;
|
||||
if (idx == 0) {
|
||||
result = stat(idx)->delay_type();
|
||||
} else {
|
||||
result = combine_delays(result, stat(idx)->delay_type());
|
||||
}
|
||||
}
|
||||
|
||||
/* If we don't have a default statement we don't know for sure
|
||||
* that we have a delay. */
|
||||
if (!def_stmt) result = combine_delays(NO_DELAY, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetCondit::delay_type() const
|
||||
{
|
||||
DelayType result;
|
||||
|
||||
if (else_) {
|
||||
result = combine_delays(if_->delay_type(), else_->delay_type());
|
||||
} else {
|
||||
result = if_->delay_type();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DelayType NetEvWait::delay_type() const
|
||||
{
|
||||
return DEFINITE_DELAY;
|
||||
}
|
||||
|
||||
DelayType NetForever::delay_type() const
|
||||
{
|
||||
return statement_->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetPDelay::delay_type() const
|
||||
{
|
||||
if (expr_) {
|
||||
return delay_type_from_expr(expr_);
|
||||
} else {
|
||||
if (delay() > 0) {
|
||||
return DEFINITE_DELAY;
|
||||
} else {
|
||||
if (statement_) {
|
||||
return statement_->delay_type();
|
||||
} else {
|
||||
return NO_DELAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelayType NetRepeat::delay_type() const
|
||||
{
|
||||
return get_loop_delay_type(expr_, statement_);
|
||||
}
|
||||
|
||||
DelayType NetTaskDef::delay_type() const
|
||||
{
|
||||
return proc_->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetUTask::delay_type() const
|
||||
{
|
||||
return task()->task_def()->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetWhile::delay_type() const
|
||||
{
|
||||
return get_loop_delay_type(cond_, proc_);
|
||||
}
|
||||
|
|
|
|||
14
netlist.h
14
netlist.h
|
|
@ -1640,6 +1640,7 @@ class NetUDP : public NetNode {
|
|||
PUdp *udp;
|
||||
};
|
||||
|
||||
enum DelayType { NO_DELAY, ZERO_DELAY, POSSIBLE_DELAY, DEFINITE_DELAY };
|
||||
|
||||
/* =========
|
||||
* A process is a behavioral-model description. A process is a
|
||||
|
|
@ -1689,6 +1690,9 @@ class NetProc : public virtual LineInfo {
|
|||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
// Recursively checks to see if there is delay in this element.
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
friend class NetBlock;
|
||||
NetProc*next_;
|
||||
|
|
@ -1896,6 +1900,7 @@ class NetBlock : public NetProc {
|
|||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
const Type type_;
|
||||
|
|
@ -1939,6 +1944,7 @@ class NetCase : public NetProc {
|
|||
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -2012,6 +2018,7 @@ class NetCondit : public NetProc {
|
|||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual int match_proc(struct proc_match_t*);
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetExpr* expr_;
|
||||
|
|
@ -2229,6 +2236,7 @@ class NetEvWait : public NetProc {
|
|||
const svector<NetEvProbe*>&events);
|
||||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetProc*statement_;
|
||||
|
|
@ -2296,6 +2304,7 @@ class NetForever : public NetProc {
|
|||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetProc*statement_;
|
||||
|
|
@ -2368,6 +2377,7 @@ class NetPDelay : public NetProc {
|
|||
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
bool emit_proc_recurse(struct target_t*) const;
|
||||
|
||||
|
|
@ -2392,6 +2402,7 @@ class NetRepeat : public NetProc {
|
|||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetExpr*expr_;
|
||||
|
|
@ -2473,6 +2484,7 @@ class NetTaskDef {
|
|||
NetNet*port(unsigned idx);
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetScope*scope_;
|
||||
|
|
@ -2541,6 +2553,7 @@ class NetUTask : public NetProc {
|
|||
virtual void nex_output(NexusSet&);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetScope*task_;
|
||||
|
|
@ -2565,6 +2578,7 @@ class NetWhile : public NetProc {
|
|||
virtual void nex_output(NexusSet&);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
|
||||
private:
|
||||
NetExpr* cond_;
|
||||
|
|
|
|||
Loading…
Reference in New Issue