Re: [sv-bc] Search order for functions/tasks in modules, $unit and packages

From: Clifford E. Cummings <cliffc_at_.....>
Date: Fri Aug 26 2005 - 15:12:48 PDT
Hi, All -

I find myself in disagreement with Gord on a few of these, so I guess we do 
need people to voice opinions.

See below.

At 01:19 PM 8/26/2005, Gordon Vreugdenhil wrote:

>Let me take a crack at the name resolution scenarios
>that Mark raised and add a few more really bad cases.
>
>Since forward references to subprograms (tasks/functions) are
>historically legal, they must be treated a bit differently.
>
>Here is a semi-operational description of what I think the
>combination of the P1800 LRM rules and historical behavior requires:
>     1) a task/function reference cannot be resolved upwards
>        from a scope until the scope (and possibly parents) are
>        complete.
>     2) a tack/function reference does inspect imports in an
>        eager manner but doesn't look upwards until (1) is
>        satisfied.

I can't find the definition of "eager"    ;-)

But I think I disagree. I don't think package::* functions and tasks are 
"eagerly" imported.

Maybe this is a tool problem that may have to change the way we think about 
it, but I am of the opinion that local function and task calls do not cause 
immediate package::* importation. I believe the module or $unit is read to 
see if functions and tasks have been defined and if they have not been 
defined, the tool then imports the tasks and functions; otherwise, we get 
very different results by putting local module task and function 
declarations at the beginning of a file from putting them at the end of a 
file. Very un-Verilog-like behavior.

This impacts some of the examples below.

>     3) all other non-type resolution that escapes to $unit must
>        also be deferred but is done in an "eager" manner in the
>        intervening scopes.
>     4) any identifier is located upwards, including $unit seen
>        "so far" and its imports and resolution occurs immediately
>        if the identifier can be resolved to a type.
>     5) a "potentially visible name" becomes directly visible as
>        early as possible but "upwards" potential visibility
>        can be deferred by earlier rules.
>
>
>Not the most obvious set of rules, but I think that this
>is pretty close.
>
>Here are the implications of this for each of the designs:
>
>
>1)
>
>function int fn();
>   return 0;
>endfunction
>
>module m();
>int x;
>initial x = fn(); // which fn() does this bind to?
>
>function int fn()
>   return 1;
>endfunction
>
>endmodule
>
>
>In "x = fn()", fn means m.fn by rule 1.

I agree.

>2)
>
>package p;
>function int fn();
>   return 0;
>endfunction
>endpackage
>
>module m();
>import p::*;
>int x;
>initial x = fn(); // which fn() does this bind to?
>
>function int fn()
>   return 1;
>endfunction
>endmodule
>
>
>By rule 2, fn() binds to p::fn, making it directly visible
>in m.  This causes the declaration of m.fn to produce an error.

I disagree. I don't think we even start looking inside of package::* until 
we know if the function or task has been declared locally.

I believe the function called should be m.fn.

>3)
>
>package p;
>function int fn();
>   return 0;
>endfunction
>endpackage
>
>import p::*;
>
>module m();
>int x;
>initial x = fn(); // which fn() does this bind to?
>
>function int fn()
>   return 1;
>endfunction
>endmodule
>
>
>By rule 2, fn() binds to m.fn since you don't inspect
>the parent's import until the module scope is closed.
>
>This also implies that "fn" is not imported into
>$unit and thus declaring a new "fn" inside $unit
>would be legal.

I agree.

>4)
>
>package p;
>function int fn();
>   return 0;
>endfunction
>endpackage
>
>import p::*;
>
>module m();
>int x;
>initial x = fn(); // which fn() does this bind to?
>endmodule
>
>function int fn()
>   return 1;
>endfunction
>
>
>This is an error.  By rule 1 & 2, upon completing the module
>scope, "fn" is found via the import.  $unit::fn then conflicts
>with the visible p::fn.

I disagree. I believe $unit.fn is used and the $unit.package::* version is 
never imported. Again, it is very un-Verilog-like to get different results 
based on where a function or task is declared within a file.

>5)
>      module m;
>      parameter p = 1;
>      function int fn();
>         return 0;
>      endfunction
>      if (p) begin:b   // generate
>          reg x = fn();
>          function int fn();
>              return 1;
>          endfunction
>      end
>      endmodule
>
>
>fn() binds to m.b.fn() since it is not resolved until the
>close of the generate scope.

I agree.

>6)
>      // file mode compilation unit
>      module m;
>         int x = fn();
>      endmodule
>      function int fn();
>          return 1;
>      endfunction
>
>
>No error.  The foward reference is resolved in $unit
>when $unit is closed.

I agree.

>7)
>      // file mode compilation unit
>      module m;
>         int x = a;   // error?
>      endmodule
>      localparam a = 1;
>
>
>No error.  "a" is not resolved until $unit is closed.

I disagree. I believe this is an error, but only because variables, wires, 
parameters, etc. declarations have always been required before use. I 
believe this is the way current compilers are treating this.

>8)
>
>      typedef int T;
>      module m;
>         T x;
>         typedef real T;
>         T y;
>      endmodule
>
>
>This one is nasty.  By rule 4,  the $unit version of T
>is visible in "m" during the declaration of x.  But
>since this isn't an import, there is no expectation that
>"T" can't be redefined in m.  This implies that this
>design is legal with x being an int and y being a real.

Nasty indeed! But I believe this is an error. I don't think you should be 
able to change the definition of a type after it has been used with an 
existing definition. Of course, put the T x; declaration after the typedef 
real T; declaration and only the local typedef is used and is legal.

>9)
>     module foo;
>       reg x;
>
>       initial begin:b
>         automatic reg y = x;
>         automatic reg x;
>       end
>     endmodule
>
>
>Similar case to (8) but follows rule (3).

I am not as sure about this one but I still believe this is illegal. 
Redefinition of x after it was first legally used in another form.

>I am not at all happy by my read of things in terms of
>the rule set that I outlined above.
>
>For types we *must* have early resolution due to parse
>issues.  And for historical reasons, we really need to
>preserve the subprogram resolution behavior.
>
>So, why not require that all non-subprogram resolution
>be done in the same manner as types *with* the additional
>requirement that any non-imported escaping reference
>becomes a "reserved" identifier in the referring scope
>so that no local redefinition of the name is permitted.
>
>Then subprograms are the only case where we have special
>rules.
>
>
>Such an approach would make the egregiously bad cases
>(8 & 9) illegal and, if I had my way, would also make
>7 illegal since "a" is a non-subprogram reference.
>
>
>
>Anyways, feedback and discussion is clearly welcome on
>this.
>
>
>Gord.
>
>
>--
>--------------------------------------------------------------------
>Gordon Vreugdenhil                                503-685-0808
>Model Technology (Mentor Graphics)                gordonv@model.com

Regards - Cliff



----------------------------------------------------
Cliff Cummings - Sunburst Design, Inc.
14314 SW Allen Blvd., PMB 501, Beaverton, OR 97005
Phone: 503-641-8446 / FAX: 503-641-8486
cliffc@sunburst-design.com / www.sunburst-design.com
Expert Verilog, SystemVerilog, Synthesis and Verification Training
Received on Fri Aug 26 15:13:06 2005

This archive was generated by hypermail 2.1.8 : Fri Aug 26 2005 - 15:14:28 PDT