ModelSim: Forward references cause errors

P

Paul Urbanus

Guest
I have inherited a project to which I need to add some functionality.
Most of the modules are written in verilog, and the remainder in vhdl.
When I try and compile the verilog files in ModelSim Designer (in PE
mode), version 6.1f, the compiler gives me errors related to forward
references.

Consider the following two lines in a verilog file:


129: localparam kAddressMax = kAddressMin+7;
130: localparam kAddressMin = 0;

Notices that kAddressMin is referenced before it is defined (forward
reference). ModelSim doesn't like this and generates the following error
message:

** Error: C:/projects/foo/foo.v(129): Undefined variable: kAddressMin.
** Error: C:/projects/foo/foo.v(130): 'kAddressMin' already declared in
this scope.

The odd thing is that the above synthesize fine in Altera Quartus 8.1.

Are forward references such as the above illegal in verilog? Does
ModelSim flag this as a valid error, but the Quartus synthesis tool is
more forgiving?

BTW, there are many other similar definitions across several files. I am
primarily a vhdl coder, with just a bit of verilog hacking, so I don't
know if this is 'legal' verilog code. If not, I need to feed this back
to my customer so these files can be cleaned up and further coding is
restricted to legal constructs.

TIA
Urb
 
On Tue, 20 Jan 2009 11:30:58 -0600, Paul Urbanus wrote:

129: localparam kAddressMax = kAddressMin+7;
130: localparam kAddressMin = 0;

Notices that kAddressMin is referenced before it is defined (forward
reference). ModelSim doesn't like this and generates the following error
message:

** Error: C:/projects/foo/foo.v(129): Undefined variable: kAddressMin.
** Error: C:/projects/foo/foo.v(130): 'kAddressMin' already declared in
this scope.

The odd thing is that the above synthesize fine in Altera Quartus 8.1.

Are forward references such as the above illegal in verilog? Does
ModelSim flag this as a valid error, but the Quartus synthesis tool is
more forgiving?
Yes, I believe this is so. Almost everywhere in Verilog,
things must be declared before being referenced. Your
original code is wrong; Quartus's parser (actually
Verific's) is tolerating it for some reason. Surely it
cannot be that this code has never been simulated....?

There are various situations that appear to be exceptions
to the declare-before-use rule (I say "appear", because
the whole name resolution thing in Verilog is far from
simple and carries a heavy burden of historical baggage).
The most obvious are:

1) Module names
~~~~~~~~~~~~~~~
You can write a module instance without needing to create
the module first (unlike VHDL where the entity or component
you're instantiating must already exist). At elaboration
time, the simulator rummages around in its library or other
collection of modules and complains if it fails to find
the instanced module. As usual there are many complications
(-y and -v options, libraries and configurations, yadda, yadda)
but generally you don't need to worry about compilation order
of modules relative to one another.

2) Hierarchical or cross-module references
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can make reference to something in a different scope
without compiling that other thing first. This will never
happen in synthesisable code, because synthesis doesn't do
cross-module or hierarchical reference, but it matters for
testbenches. Again there are some awkward wrinkles relating
to named scopes within a module, and SystemVerilog with its
structs and classes makes things MUCH more difficult, but
it's a reasonable starting point to assume that hierarchical
(dotted) references don't get resolved until elaboration time.

3) Task and function calls
~~~~~~~~~~~~~~~~~~~~~~~~~~
For some reason that completely escapes my understanding,
some folk like to put all their function and task declarations
at the very end of a module. To support this, Verilog
effectively treats all function and task calls as though they
were hierarchical references, and postpones their resolution
until elaboration time.

4) Implicit wire declaration (all together now... UGH!)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you wire up a module instance's port to some signal that
has not yet been declared, then Verilog will create an
implicit one-bit wire for you. Indeed, if you try to
declare that signal explicitly, later in the module, you'll
get a double-definition error. Strictly for hooligans,
netlist-bashers and others of diminished moral judgment.

Good luck.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Jonathan Bromley wrote:

If you wire up a module instance's port to some signal that
has not yet been declared, then Verilog will create an
implicit one-bit wire for you. Indeed, if you try to
declare that signal explicitly, later in the module, you'll
get a double-definition error.
Incredible.
Thanks for the tip.
I'll stick with regs.

-- Mike Treseler
 
On Tue, 20 Jan 2009 11:02:12 -0800, Mike Treseler wrote:

If you wire up a module instance's port to some signal that
has not yet been declared, then Verilog will create an
implicit one-bit wire for you.[...]

Incredible.
Any sufficiently advanced technology is
indistinguishable from magic :)

Thanks for the tip. I'll stick with regs.
That, I'm afraid, won't help you. Consider this:

module weird_gate(input A, B, output reg Y);
always @(A, B)
Y = B | ~A; // "implies" gate
endmodule // That module was OK.

module top(...);
reg a, b; // will drive an internal instance
wire c; // for the output of that instance

weird_gate the_implication (.A(a), .B(B), .Y(c));
// note spelling mistake here---------^
...
endmodule // AAARGH, this module compiles....

Now, when I compile "top", a single-bit wire B will be
created implicitly by the port connection. This may
or (more likely) may not be what you had in mind.

Those of us who prefer our programming languages
to do what we tell them to do are likely to be
happier if they write, at the head of every
source file, this little spell taken from my
well-thumbed and only slightly potion-stained
copy of The Verilog Adept's Grimoire and Runes:

`default_nettype none

And now the implied, default declaration of B is
nothing at all, and so you get a compile-time
error and your spelling mistake is unmasked.

Note for beginners: compiler directives such as
`default_nettype should be written using a quill
pen on a vellum palimpsest for the best effect.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Thanks Mike and Jonathan for your explanations.

BTW, I added the `default_nettype directive to files that were compiling
without error, and the results were not good. I discovered that while
the module ports were defined, there was not a corresponding list of
wires/regs for these port signals. I friend who is very verilog-aware
indicated that such was NOT good verilog coding style. I suspect you
would agree with this sentiment?

Urb
 
On Tue, 20 Jan 2009 23:24:59 -0600, Paul Urbanus wrote:

BTW, I added the `default_nettype directive to files that were compiling
without error, and the results were not good. I discovered that while
the module ports were defined, there was not a corresponding list of
wires/regs for these port signals. I friend who is very verilog-aware
indicated that such was NOT good verilog coding style. I suspect you
would agree with this sentiment?
First off, my apologies; when ranting about `default_nettype none,
I always forget to mention that it forces you to be explicit in
declaring the net type of all ports unless they are "reg" outputs.

So:

module M (input a, output [3:0] y, output reg q);

is OK if you DON'T use `default_nettype none,
but will fail to compile if you do. So you need:

`default_nettype none
module M(input wire a, output wire [3:0] y, output reg q);

My personal feeling is that the added verbosity is a small
price to pay for avoiding the implicit-wire trap. But not
everyone agrees. Your call :) It's also worth noting that
SystemVerilog changes the rules of the game here in a number
of different ways, and `default_nettype may not be the best
solution if you have SystemVerilog-aware tools. For a
reasonably thorough take on those issues, see
Cliff Cummings's recent paper

http://www.sunburst-design.com/papers/CummingsSNUG2007Boston_DotStarPorts.pdf

Again, apologies for the oversight.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jonathan Bromley wrote:
On Tue, 20 Jan 2009 11:30:58 -0600, Paul Urbanus wrote:

129: localparam kAddressMax = kAddressMin+7;
130: localparam kAddressMin = 0;

Notices that kAddressMin is referenced before it is defined (forward
reference). ModelSim doesn't like this and generates the following error
message:

** Error: C:/projects/foo/foo.v(129): Undefined variable: kAddressMin.
** Error: C:/projects/foo/foo.v(130): 'kAddressMin' already declared in
this scope.

The odd thing is that the above synthesize fine in Altera Quartus 8.1.

Are forward references such as the above illegal in verilog? Does
ModelSim flag this as a valid error, but the Quartus synthesis tool is
more forgiving?

Yes, I believe this is so. Almost everywhere in Verilog,
things must be declared before being referenced. Your
original code is wrong; Quartus's parser (actually
Verific's) is tolerating it for some reason. Surely it
cannot be that this code has never been simulated....?
The original code certainly *is* correct. It is an unfortunate quirk
of Verilog that forward references (within a module) are perfectly
legal. As a Verilog compiler implementer, I have to add that it is
perfectly exasperating, too, but there you go.

Most tools handle forward references fine, but a few do not. Personally,
I think that forward references should be illegal, but the IEEE1364
does not disallow them, and many "reference" simulators handle forward
references. I'm shocked that ModelSim is complaining about them. I bet
the Cadence and Synopsis tools handle the original code just fine.

- --
Steve Williams "The woods are lovely, dark and deep.
steve at icarus.com But I have promises to keep,
http://www.icarus.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFJd3P5rPt1Sc2b3ikRAu5EAJ4iccCVm3Jispmurd3Yfu8J06WCUwCg7by7
76C/vixZo4HhfF20eYZVprY=
=WFAN
-----END PGP SIGNATURE-----
 
On Wed, 21 Jan 2009 11:14:01 -0800, Stephen Williams wrote:

[Jonathan]
Yes, I believe this is so. Almost everywhere in Verilog,
things must be declared before being referenced. Your
original code is wrong;
[Stephen Williams]
The original code certainly *is* correct. It is an unfortunate quirk
of Verilog that forward references (within a module) are perfectly
legal. As a Verilog compiler implementer, I have to add that it is
perfectly exasperating, too, but there you go.

Most tools handle forward references fine, but a few do not. Personally,
I think that forward references should be illegal, but the IEEE1364
does not disallow them, and many "reference" simulators handle forward
references. I'm shocked that ModelSim is complaining about them. I bet
the Cadence and Synopsis tools handle the original code just fine.
Stephen,

I was about to post a grovelling retraction, but I don't
think I need to; all three big-name simulators agree with
me that use of a parameter before declaration is illegal.
There has been discussion of this _ad_nauseam_ on the
SystemVerilog committees and, although I still haven't
located the LRM text that says it, I'm 99% sure that
my description was correct within its self-confessed limits.
Parameters, variables and wires must be declared before
use. Hierarchical references and references to task
and function names are resolved later, at elaboration
time, and so can legitimately be "forward references".

I would not for a moment disagree with you that Verilog
has features that make life less than simple for
compiler writers :)
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Wed, 21 Jan 2009 21:35:34 +0000, Jonathan Bromley wrote:

I still haven't located the LRM text that says
[identifiers must be declared before being referenced]

Ahah! Found it at last! The whole name resolution
thing has been mightily clarified in Std.1800-2009
drafts (which will merge 1364 Verilog and 1800
SystemVerilog); in Draft 8, clause 3.12.1 says...

Other than for task and function names
(see 23.8.1), references shall only be
made to names already defined in the
compilation unit.

Q.E.D. ...
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jonathan Bromley wrote:
On Wed, 21 Jan 2009 21:35:34 +0000, Jonathan Bromley wrote:

I still haven't located the LRM text that says
[identifiers must be declared before being referenced]

Ahah! Found it at last! The whole name resolution
thing has been mightily clarified in Std.1800-2009
drafts (which will merge 1364 Verilog and 1800
SystemVerilog); in Draft 8, clause 3.12.1 says...

Other than for task and function names
(see 23.8.1), references shall only be
made to names already defined in the
compilation unit.

Q.E.D. ...
Well, that's SystemVerilog. I can see that this rule would apply
to SV, as SV is far too complex to carry the burden of some certain
Verilog inanities, but I do not see that this applies to Verilog.
True, the intent is to support existing Verilog as much as possible,
but there are going to be conflicts where you just have to choose
one rule over the other.

Unfortunately, I think with Verilog there was no rule on this
subject, just an ecosystem of existing code and implementations.
And at least some of that ecosystem allows forward references and
that constrains me to support forward references in Icarus Verilog.
(You think forward references of variables is bad. Consider the
whole forward-reference jungle that defparams and generate syntax
together create. There is a whole chapter in the -2005 LRM on
how to cope with that particular mess.)

I have to say that given the situation, ModelSim is wrong for
Verilog code (not SystemVerilog code) if you take the position
that the IEEE1364 LRM is correct. The LRM doesn't disallow forward
references (and in fact presumes them in some instances) so we
implementors are compelled to assume they are allowed.

One can also say that the IEEE1364 LRM is wrong, or incomplete, but
that argument will only fly if the state of the art pre-IEEE1364
was to disallow forward references, or if there is some explicit
and authoritative statement of intent (i.e. errata) that can be
referenced.

In the end, of course, the rules are defined by what you can get
away with;-)

- --
Steve Williams "The woods are lovely, dark and deep.
steve at icarus.com But I have promises to keep,
http://www.icarus.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFJeKlHrPt1Sc2b3ikRAiBCAKCAnIBlvtc35enkRIskYLf4gif/oACeInn8
Jvs75uLFPuFuJA3SGrlJYvE=
=wxe0
-----END PGP SIGNATURE-----
 
On Thu, 22 Jan 2009 09:13:43 -0800, Stephen Williams wrote:

Other than for task and function names
(see 23.8.1), references shall only be
made to names already defined in the
compilation unit.
[...]
Unfortunately, I think with Verilog there was no rule on this
subject, just an ecosystem of existing code and implementations.
And at least some of that ecosystem allows forward references and
that constrains me to support forward references in Icarus Verilog.
But the heavyweight players simply don't. Even Verilog-XL (which
has no idea about V-2001, let alone SV) chokes on the forward
reference in this example:

module m;
parameter b = c+3; // illegal forward ref to 'c'
parameter c = 2;
reg a;
initial a = b;
endmodule

Now, for all I know there may be some obscure command-line
options to any or all of those tools to enable forward
referencing. But the mainstream default behaviour is
to outlaw forward refs to module-local parameters, nets
and variables. 1364 may well say nothing about it, but
that's not the only bit of Verilog on which 1364 is quiet.

(You think forward references of variables is bad. Consider the
whole forward-reference jungle that defparams and generate syntax
together create. There is a whole chapter in the -2005 LRM on
how to cope with that particular mess.)
Yes, and as I mentioned, SV-2009 goes considerably further in
clearing up the said mess. It's one of many things that makes
me very grateful that I don't write compilers for a living.

I have to say that given the situation, ModelSim is wrong for
Verilog code (not SystemVerilog code) if you take the position
that the IEEE1364 LRM is correct. The LRM doesn't disallow forward
references (and in fact presumes them in some instances) so we
implementors are compelled to assume they are allowed.
As I tried to emphasise earlier, forward references to task
and function names are OK. I am fairly sure that those
are the only kind of forward ref you will find exemplified
in 1364, although I confess I haven't checked exhaustively.

One can also say that the IEEE1364 LRM is wrong, or incomplete, but
that argument will only fly if the state of the art pre-IEEE1364
was to disallow forward references, or if there is some explicit
and authoritative statement of intent (i.e. errata) that can be
referenced.

In the end, of course, the rules are defined by what you can get
away with;-)
Sure. If it's wiggle-room you seek, then Verilog is probably
as good a place as any to start looking :-(
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
Even in the '95 version of the std--the last version I completely
implemented, I believe there was a statement in the LRM that made
parameters declare before use, at least declare before use as a
non-hierarchical name.

The interaction of default declared wires and other stuff is a real
mess, but it was there to support Verilogization of netlists, where
the common practice was not to declare anything that was 1 bit wide
because it would take 2 passes (over the instances) by the tools
writing out the netlists to get that right. The first pass to find
the interconnecting wires and write their declarations and the second
pass to write out the instances.
 
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Jonathan Bromley wrote:
On Thu, 22 Jan 2009 09:13:43 -0800, Stephen Williams wrote:
Unfortunately, I think with Verilog there was no rule on this
subject, just an ecosystem of existing code and implementations.
And at least some of that ecosystem allows forward references and
that constrains me to support forward references in Icarus Verilog.

But the heavyweight players simply don't. Even Verilog-XL (which
has no idea about V-2001, let alone SV) chokes on the forward
reference in this example:

module m;
parameter b = c+3; // illegal forward ref to 'c'
parameter c = 2;
reg a;
initial a = b;
endmodule

Hmm... Perhaps it's time for me to think about adding warnings for
this sort of forward reference. I might be suffering a delusion based
on broken memory. I personally don't have instances of the Big-3,
so I rely on others to run tests when there is some doubt as to the
conventional interpretation of some vague aspect of the language.
If XL, NC, VCS and ModelSim all agree that this is illegal, then
clearly I'm the outlier and Icarus Verilog should be fixed.

(Icarus Verilog compiles the above example in the intuitive way.)

We know from the original post that ModelSim flags this as an error,
and you are saying that Verilog-XL also flags that as an error. Those
facts alone are pretty convincing.

Sigh. Oh well, a Verilog implementer's work is never done.

- --
Steve Williams "The woods are lovely, dark and deep.
steve at icarus.com But I have promises to keep,
http://www.icarus.com and lines to code before I sleep,
http://www.picturel.com And lines to code before I sleep."
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFJefUErPt1Sc2b3ikRAgs/AJsFPjg3rOoothxItm41OKdD7STnJQCgpYTt
NYRdlDUiFm7bDF9yOyhK+UE=
=BUkt
-----END PGP SIGNATURE-----
 

Welcome to EDABoard.com

Sponsor

Back
Top