RE: [sv-ec] hierarchical references to the types (reference to class definition nested in module/program /interface)

From: Mirek Forczek <mirekf_at_.....>
Date: Fri Oct 19 2007 - 01:27:18 PDT
 
Dave,

As I can see there is an open discussion thread on 'Type parameters,
typedefs, and general BNF semantics'.
Hopefully this will address also issues of  hierarchical references to the
types rised here.

But following your answer I want to provide some additional points of view
that mayby were not expressed elsewhere.

> The alternative for accessing types across the hierarchy is to put your
types in packages.

I understand what are the possibilities in language following current state
of the LRM.
But sometimes moving types definitions into a package or unit scope,
although provide some technical solution, may not satisfy user's needs in
making reusable code.

Just consider following example of possible coding style:

module ProtocolClientA;
    typedef byte[4] data_type;

    task send(data_type data);
        ...
    endtask
    function data_type receive;
        ...
    endfunction
endmodule

module ProtocolClientB;
    typedef int[8] data_type;

    task send(data_type data);
        ...
    endtask
    function data_type receive;
        ...
    endfunction
endmodule


if '::' was allowed for accessing a typedef from module, than a following
code snippet could be used in a testbench part:

<client_type> uut();
...
<client_type>::data_type a, b;
...
uut.send(a);
b = uut.receive();


in example:

ProtocolClientA uut();
...
ProtocolClientA::data_type a, b;
...
uut.send(a);
b = uut.receive();

 
ProtocolClientB uut();
...
ProtocolClientB::data_type a, b;
...
uut.send(a);
b = uut.receive();

also this would allow to enclose the code snippet into parametrized unit:

program #(type client_type) protocol_test;

    initial
        begin
            client_type uut();
            ...
            client_type::data_type a, b;
            ...
            uut.send(a);
            b = uut.receive();
            ...
        end

endprogram

and than use it in a fairly simple way:

protocol_test#(ProtocolClientA) testA();
protocol_test#(ProtocolClientB) testB();

Now notice that:
- currently such testbench code can be done only if a protocol client
classes were implemented on a class basis,
- it cannot be done if protocol client classes were implemented on a module
basis,
(for some reason user may prefer to define clients as part of the design
hierarchy ...)

Moving types definitions to the (common) package scope is not a solution
here - it will not allow to keep same name ('data_type') for both type
definitions - which is a foundation for this reusable testbench code
construction.

And notice that the in example above none of the problems you mentioned
(hierarchical references to the parameters, forward references to the types)
occur.
So how to explain to the user: why he is forbidden to refer simple type
definitions hierarchically ?
Clearly, '::' usage limitation to the class and package scopes only is too
strong penalty, just because of some complex corner cases.

Of course a little more advanced example of  hierarchical references to the
parametrized module types will unlikely lead to hierarchical references to
parameters.
This is why the hierarchical references to parameters becomes much more
important option in SV, than it is was in Verilog where it is locked by LRM
.

It is important for SystemVerilog to keep backward compatibility with
Verilog.
But to satisfy this requirement it is enough to keep Verilog rules for
Verilog subset of constructs. New constructs of a SystemVerilog do not have
to follow exactly same rules.

Having this in mind, I believe that some of the problems you've point out ,
if considered separately, could have their solutions:

>The problem here is compilation order dependencies. In general, Verilog
does not allow you to refer to hierarchical references to parameters in
declarations because it needs to
>impose a strict ordering of parameter overrides during elaboration.
This rule in Verilog was to protect user from making circular dependencies
between parameters and to easy elaborator job.
But notice that even with hierarchical references to parameters not every
case must contain circular dependencies. Lot of cases will stand for useful
coding styles.

Just let's relax this Verilog rule in SV LRM and let the elaborator to find
the proper order of the parameters initialization or to detect and report
circular dependency ...

>Interface types are a special case because the port connection imposes an
ordering that the elaboration process can follow.
I think that the language LRM better shall not attempt to control the way
how the elaboration process is done.
It is just out of LRM scope - how the compilation and elaboration processes
are organized in each system.

An attempt to impose order of the elaboration process results in unnatural
syntax and semantic construct - as in case of interface types. The
elaborator shall be able to find the right order of processing on its own
...

>Another problem that is harder to explain is the fact that Verilog allows
modules to be referenced before being compiled. 
>Even with that flexibility, Verilog still requires simple >identifiers to
be declared before referenced. [...]. 
>There is even a stronger parsing restriction for types, [...], which
requires a type identifier to be known to be a type before it can be
referenced.
Indeed Verilog allows modules to be referenced before (or even without - for
compilation phase) their definitions. This is an important feature for
effective compilation of large netlists, where actual modules definitions
are irrelevant for the compilation task.
But - as you mentioned: even in Verilog this rule do not apply to all
definitions -  Verilog still requires simple identifiers to be declared
before referenced.

The hierarchical reference to type, especially if made with '::' operator -
as a SV construct - may require a type identifier to be known at least to be
a type name, without breaking up  backward compatibility with Verilog.
This would also imply that the module definition must come first, before a
typedef from within the module can be referenced externally.

As a result, allowing hierarchical references to types do not have to imply
allowing references to type names prior to the type definition or at least
notice that the name is a type.

Regards,
Mirek

-----Original Message-----
From: Rich, Dave [mailto:Dave_Rich@mentor.com] 
Sent: 12 października 2007 18:54
To: Mirek Forczek; Vreugdenhil, Gordon; danielm
Cc: sv-ec@server.eda.org
Subject: RE: [sv-ec] reference to class definition nested in module/program
/interface

Mirek,

You've should look back at the e-mail threads on the sv-bc for the last
3 months.

The alternative for accessing types across the hierarchy is to put your
types in packages.

The key thing that Verilog has that none of the other OO languages you
mention have is parameterized hierarchical elaboration. It is essentially a
distinct form of object orientation that gives you the ability to do
hierarchical references which the other languages don't have. 

The key thing that Verilog doesn't have that that SV adds is a type system
similar to the other OO languages you mention. Problems come in is when you
try to blend the two systems.

The easiest to problem to explain is the parameterized elaboration. If you
have:

module mod #(parameter N=2)();

typedef int arr[N];

endmodule

and then you try to 

module bod;

mod::arr A;

endmodule

module top;

mod  #(3); m1()
mod  #(4); m2()
bod bod();
endmodule


Which instance of mod would you be referring to in bod?

Then there's

module bod;

top.m1.arr A;

endmodule

The problem here is compilation order dependencies. In general, Verilog does
not allow you to refer to hierarchical references to parameters in
declarations because it needs to impose a strict ordering of parameter
overrides during elaboration. Interface types are a special case because the
port connection imposes an ordering that the elaboration process can follow.

Another problem that is harder to explain is the fact that Verilog allows
modules to be referenced before being compiled. Even with that flexibility,
Verilog still requires simple identifiers to be declared before referenced.
This is a parsing requirement that came from Pascal, one of Verilog's
progenitors. There is even a stronger parsing restriction for types, which I
am currently writing up a mantis issue on, which we agreed to in a recent
face-to-face meeting on this subject, which requires a type identifier to be
known to be a type before it can be referenced.

There are two ways to accomplish this across the hierarchy: one is through
packages, and the other is though hierarchical type parameterization.

for example, through packages
package pkg;
typedef struct {int A;} s_t;
endpackage

module A();

pkg::s_t i;

endmodule

module B#(type T=int)();

pkg::s_t i;

endmodule

module top;

A a();
B b();

initial a.i=b.i; // legal assignment

endmodule

Through hierarchical type parameterization.


module A#(type T=int)();

T i;

endmodule

module B#(type T=int)();

T i;

endmodule

module top;

typedef struct {int A;} s_t;

A #(s_t) a();
B #(s_t) b();

initial a.i=b.i; // legal assignment

endmodule



-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Fri Oct 19 01:27:54 2007

This archive was generated by hypermail 2.1.8 : Fri Oct 19 2007 - 01:28:02 PDT