[sv-bc] Re: [sv-ec] variable initialization at declaration

From: Steven Sharp <sharp_at_.....>
Date: Fri Apr 25 2008 - 15:09:36 PDT
I had put off responding to this email, but now the issue has come up
again in the BC.


>From: "danielm" <danielm@aldec.com.pl>

>LRM:
>" In Verilog, an initialization value specified as part of the declaration
>is executed as if the assignment were made from an initial block, after
>simulation has started. In SystemVerilog, setting the initial value of a
>static variable as part of he variable declaration (including static class
>members) shall occur before any initial or always blocks are started."
>
>Is initialization really a part of declaration - if so then newly declared
>identifier is visble after ';', and in initialization phase this identifier
>remains not declared. I mean what should happened for below code:
> 
>module top;
>    parameter p=123;
>    initial begin : _label
>        int p=p; //this is circular illegal assignment p=p, or at the moment
>of initialization p from outer scope is still visible?
>        $display(p);    
>    end
>endmodule


My opinion has been that this should be treated as a reference to the p
in the outer scope, which requires that the identifier not become visible
until after its full declaration, including the initializer.  The main
reason is that this could be useful in some situation, while the circular
assignment is useless.

This argument is weaker now that Shalom has pointed out a possible use
for the circular reference, to invoke a method:

	Colors c = c.first;
	
This is meaningful because this method is unusual in not requiring the
value of the variable that is the object of the method.

Another argument on this is that it avoids the question of what the
value of the variable is before it is initialized.  Some people seem
to be assuming that a circular reference is inherently illegal, but
there is no such rule in the LRM.  If the circular reference is possible,
and no rule is added to make it illegal, then the behavior should be
defined.  

It seems to me that the definition is pretty obvious: it has the default
initialization value.  This makes sense in a couple of ways.  First, one
expects "p=p" to have no effect.  So "int p=p;" should have the same
effect as "int p;" and that initializes p to its default initialization
value of 0.  Second, you can regard the process of initialization as
first initializing to the default initialization value, and then if there
is an explicit initializer, executing that.  So I don't think there is
a big need to avoid the circular reference.  Also, if hierarchical
references are allowed in initializers, you cannot prevent the circular
reference, so you need to define it anyway.

Then there are the historical precedents.  For a net with a continuous
assignment on the net declaration, the assignment has always been able
to refer to the net being declared, since that is what Verilog-XL did.
Unlike variable initializers, there are situations where it makes sense
to refer to the left-hand-side net in the assignment, to create a
combinational loop:

	wire q = en ? d : q;
	
While this may not be a recommended modeling style, it is a valid way
to describe a transparent latch.

Also, back before Verilog-2001, there was no way that q could refer to
anything but the q on the left-hand-side.  Without $unit or generate
scopes, the scopes where nets could be declared were never nested inside
any other scope where a different q could be found.  So if it didn't
refer to the net on the LHS, it would have to be an error.  So the
usefulness argument favored letting the RHS refer to the LHS.  If the
decision were being made today, the scope argument would not be valid
any more.  But I assume that this is something that is already well enough
established that it cannot be changed.

Another precedent would be a parameter declared inside a generate scope,
with a default value that refers to the same name:

  module top;
    parameter p = 41;
    
    if (1) begin
      localparam p = p + 1'b1;
      initial $display(p);
    end
  endmodule
  
I don't know if there is anything in the LRM that addresses this.  I
don't know whether implementations have treated it consistently.  The
one I tested treats this as a reference to the outer p.  I think that
makes the most sense.

As with variables, a reference to the outer p might be useful, while a
reference to the inner one is not.  The problem of circularity is worse
for parameters, since they don't have a concept of a default value other
than the one specified for them.  They may not even have a type, but get
it from the value, which makes the type circular also.  And the value is
not allowed to use hierarchical references, so this prevents that other
way of getting a circular reference.  That makes it more useful to avoid
this way of getting it.

Overall, I am still inclined to make a variable visible only after the
initializer.  However, it isn't a strong opinion.

Steven Sharp
sharp@cadence.com


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Fri Apr 25 15:11:18 2008

This archive was generated by hypermail 2.1.8 : Fri Apr 25 2008 - 15:12:17 PDT