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:
Cary R 2008-04-22 11:32:10 -07:00 committed by Stephen Williams
parent 7b705a0212
commit c38e8182c2
8 changed files with 274 additions and 110 deletions

View File

@ -1,7 +1,7 @@
#ifndef __compiler_H #ifndef __compiler_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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. */ /* Warn about legal but questionable module port bindings. */
extern bool warn_portbinding; 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. */ /* This is true if verbose output is requested. */
extern bool verbose_flag; extern bool verbose_flag;

View File

@ -21,7 +21,7 @@
# #
SHELL = /bin/sh SHELL = /bin/sh
VERSION = 0.8 VERSION = 0.9.devel
prefix = @prefix@ prefix = @prefix@
exec_prefix = @exec_prefix@ exec_prefix = @exec_prefix@

View File

@ -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 .SH NAME
iverilog - Icarus Verilog compiler 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 timescales are inconsistent, and simulation timing can be confusing
and dependent on compilation order. 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" .SH "SYSTEM FUNCTION TABLE FILES"
If the source file name as a \fB.sft\fP suffix, then it is taken to be 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 a system function table file. A System function table file is used to

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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) { } else if (strcmp(name,"timescale") == 0) {
if (! strchr(warning_flags, 't')) if (! strchr(warning_flags, 't'))
strcat(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) { } else if (strcmp(name,"no-implicit") == 0) {
char*cp = strchr(warning_flags, 'i'); char*cp = strchr(warning_flags, 'i');
if (cp) while (*cp) { if (cp) while (*cp) {
@ -703,7 +708,7 @@ int main(int argc, char **argv)
if (version_flag || verbose_flag) { if (version_flag || verbose_flag) {
printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n"); 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); puts(NOTICE);
if (version_flag) if (version_flag)
@ -841,4 +846,3 @@ int main(int argc, char **argv)
return 0; return 0;
} }

View File

@ -3277,6 +3277,29 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const
verinum(1)); verinum(1));
} while (0); } 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; return true;
} }

109
main.cc
View File

@ -1,6 +1,6 @@
const char COPYRIGHT[] = 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 * 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 * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * 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" # include "config.h"
@ -113,6 +110,7 @@ FILE *depend_file = NULL;
bool warn_implicit = false; bool warn_implicit = false;
bool warn_timescale = false; bool warn_timescale = false;
bool warn_portbinding = false; bool warn_portbinding = false;
bool warn_inf_loop = false;
bool error_implicit = false; bool error_implicit = false;
@ -434,6 +432,9 @@ static void read_iconfig_file(const char*ipath)
case 'i': case 'i':
warn_implicit = true; warn_implicit = true;
break; break;
case 'l':
warn_inf_loop = true;
break;
case 'p': case 'p':
warn_portbinding = true; warn_portbinding = true;
break; break;
@ -830,103 +831,3 @@ int main(int argc, char*argv[])
return des? des->errors : 1; 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.
*/

View File

@ -2417,3 +2417,207 @@ const NetProc*NetTaskDef::proc() const
{ {
return proc_; 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_);
}

View File

@ -1640,6 +1640,7 @@ class NetUDP : public NetNode {
PUdp *udp; PUdp *udp;
}; };
enum DelayType { NO_DELAY, ZERO_DELAY, POSSIBLE_DELAY, DEFINITE_DELAY };
/* ========= /* =========
* A process is a behavioral-model description. A process is a * 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; virtual void dump(ostream&, unsigned ind) const;
// Recursively checks to see if there is delay in this element.
virtual DelayType delay_type() const;
private: private:
friend class NetBlock; friend class NetBlock;
NetProc*next_; NetProc*next_;
@ -1896,6 +1900,7 @@ class NetBlock : public NetProc {
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*); virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
const Type type_; const Type type_;
@ -1939,6 +1944,7 @@ class NetCase : public NetProc {
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
@ -2012,6 +2018,7 @@ class NetCondit : public NetProc {
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*); virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
NetExpr* expr_; NetExpr* expr_;
@ -2229,6 +2236,7 @@ class NetEvWait : public NetProc {
const svector<NetEvProbe*>&events); const svector<NetEvProbe*>&events);
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
NetProc*statement_; NetProc*statement_;
@ -2296,6 +2304,7 @@ class NetForever : public NetProc {
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
NetProc*statement_; NetProc*statement_;
@ -2368,6 +2377,7 @@ class NetPDelay : public NetProc {
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
bool emit_proc_recurse(struct target_t*) 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 NexusSet* nex_input(bool rem_out = true);
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
NetExpr*expr_; NetExpr*expr_;
@ -2473,6 +2484,7 @@ class NetTaskDef {
NetNet*port(unsigned idx); NetNet*port(unsigned idx);
void dump(ostream&, unsigned) const; void dump(ostream&, unsigned) const;
DelayType delay_type() const;
private: private:
NetScope*scope_; NetScope*scope_;
@ -2541,6 +2553,7 @@ class NetUTask : public NetProc {
virtual void nex_output(NexusSet&); virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
NetScope*task_; NetScope*task_;
@ -2565,6 +2578,7 @@ class NetWhile : public NetProc {
virtual void nex_output(NexusSet&); virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type() const;
private: private:
NetExpr* cond_; NetExpr* cond_;