Re: [sv-bc] Assignment compatibility after elaboration

From: Greg Jaxon <Greg.Jaxon_at_.....>
Date: Tue Sep 04 2007 - 20:56:48 PDT
Gordon,

  Thanks for the encouraging reply.  I agree that the LRM lacks
some of these important concepts, but I see this as a problem with
the LRM, not with the concepts...  (more below)

Gordon Vreugdenhil wrote:
> 
> 


>>> Surya Pratik Saha wrote:

>>>> module bottom;
>>>>   parameter p = 1;
>>>>   typedef struct {int x; int y;} st;
>>>>   st s;
>>>> endmodule
>>>>
>>>> module top;
>>>>   bottom #(2) b1();
>>>>   bottom #(3) b2();
>>>>   initial begin
>>>>      b1.s = b2.s;
>>>>   end
>>>> endmodule

>> Gordon Vreugdenhil wrote:
>>>
>>> This should be illegal.
>>>
>>> SV does NOT do structural compatibility -- for a struct, each
>>> elaborated struct declaration is a unique type.  Here there are
>>> two "instance paths" to the types so the types are distinct
>>> and the assignment is illegal.

> Greg Jaxon wrote:
>> I have a follow-up question...
>>
>> The two types "st" can be distinguished in two ways:
>>
>>   1) They are declared by different specializations of the module
>> template "bottom".
>>
>>   2) They are declared by different instances of the "bottom" module.
>>
>> Gordon is faithful to the LRM when he appeals to reason #2 to answer Surya.
>> I wonder, though, whether it would be more sensible to rely solely on reason #1.
>>
>> Is there any functional dependence a type can have on its "home instance"?
>> I suppose classes whose methods have side-effects outside the class members
>> would be the canonical example - can this arise in SV?   

> Sure.
> 
>    module bottom;
>       int x;
>       class C;
>           function void incr();
>               x++;
>           endfunction
>       endclass
>    endmodule
> 
> "x" here is like a static member.  In fact, a static member
> would also be a determinable way of discovering whether
> an implementation was compliant to the specs requirements.
> 
> 
>> If so, do all such dependences arise from "class" types?
> 
> I believe so.

Now let's consider the "depends upon" side of this arc...

A class type's identity can depend upon instances of what?
Just modules (and interfaces), or can it also refer to
static data inside lexically more global class declarations?

Undoubtedly a class type's identity can be tied to physical instances
of certain design components by using static data from such instances.
Is this difference between the expressive power of classes and the
simpler "structural" types significant?

Structs and unions can have class fields.  In the recursive definition
of "matching type", such structs will only match if all their fields
also  have matching types, i.e. identical classes dependent upon
the identical component instances.  This allows two struct types
to be instanced from the same lexical source and yet not match, giving
an appearance of instance-specificity.  But instance-specificity is not
a necessary property of every struct/union type (unless we define it so).

Why do that?

On behalf of the synthesis products, I want to object to making
this definition.  I'll note that currently (and probably for some time
to come), no synthesis product implements SV classes (except for static
classes, or those which by definition are incapable of external data reference).
SV class objects are dynamic pointers - a behavioral abstraction
generally considered too high level for RTL synthesis.  This leaves
the synthesis subset with no known benefit from instance-specificity
and a potentially onerous cost.  This was why I said:

>> Working from existing synthesis technology, I see a minor disconnect in the
>> type system based on instances.  In practice, designers may specialize a
>> module template a few times, but replicate them sometimes hundreds or thousands
>> of times.  To keep compile costs down, perfect replicas aren't made unique
>> until quite late in the compiler flow - place and route, maybe even later.

> There is no concept of "specialization" for modules.  Modules are
> instantiated; parameterized classes are specialized.

The LRM doesn't articulate this concept, but I assure you it exists:
"4 bit signed carry/save" is a specialization of "adder"; folks often
load such a design from elaborated RTL and then proceed to instantiate
lots of them with no further involvement of the synthesis front-end.
The universe of discourse within that front-end refers to module template
specializations; the synthesis-subset of defparams are just a syntactically
clumsier way of controlling specialization.

Contrary to the LRM, in a design DB, the concept of a module instantiation
is usually nothing more than another edge in a large DAG.  The meaty
nodes of that graph start off being labeled as module template
specializations.  They are only split into instantiations as needed to
further specialize for optimal timing, area, congestion, etc.

> Implementations may *choose* to optimize by determining how to
> safely fold together the behavior from various instantiations
> of a module but that is strictly an optimizations.  The LRM view
> of the relationship is what matters.

I understand this viewpoint, but for the last few years I've been bewildered
about how it aligns with reality.  It doesn't.  This isn't simply an
optimization.  No CSE hash tables are consulted to produce these DAGs;
they are synthesized by a process no different in principle from wiring
up the RTL for a sequential block.

>> To insist that we be able to distinguish the replicas during elaboration
>> (when type information can influence logic) seems excessive.  Is it
>> really necessary?
> 
> Again, what an optimization can decide to safely do is up to
> the implementation; the LRM conceptualization is based on
> instantiations.

Gord is absolutely right that this is how the LRM is now.
I just cannot yet see why it /must/ be this way.
I think struct, union, and enum type identities can safely
be tied to unique module specializations.
Indeed, this is all that I have been able so far to tie
them to in the synthesis implementation I work on; and
the SV designers seem to think it follows their mental
model of elaboration naturally enough.

What Gord calls an optimization, I think of as a simplification
 - more than that: an architectural choice in favor of simplicity.
Do not unnecessarily multiply neither module instances nor type identities.

Here is what synthesis would require to implement the LRM's
definition:  Any module or interface which declared a struct, union, or
enum type would need to take a new implicit parameter "instance_identity"
to build into these "strong" type identities and to pass on to down
designs via type parameters as needed.

Each design instance would then require individualized elaboration
(or at least some last-minute substitution of the actual instance
identity before types are compared).   Of course, $instance_id can be
added to the specialization recipe - they're not /my/ CPU cycles!
Before spending my customers' elaboration time spamming him with
personalized chain letter .db, I want to be sure this is what the world
really wants.  Of course, for classes, it IS what you want.  But
structs are not as complex as classes, is it surprising that you might
expect less from them?

You can look at the absence of such a hidden parameter as
  - an LRM conformance bug, or as
  - the discovery of a simpler model for the language semantics.
Seeing it as a bug requires conceiving of instance-specificity
as being the designer's intent when (s)he writes down an enumeration
or a struct layout.  Instance-specific structs, unions, and enums
might on rare occasions be a nifty way to propagate hierarchical
info, but that is rarely needed information.  Instance-specificity
seems (to me) to be an optional and somewhat marginal property.
In fact, it seems excessively finicky, because it picks up
dependences on hierarchical paths that are usually irrelevant to
the purely structural nature of data access to struct fields.

Why is this bundled into a straightforward idea like field aggregation?
Do I have to go back to using macros for field access to get the
original lightweight concept we lifted from Pascal, C, Fortran90, et al?

I am NOT arguing for structural-equivalence here.  I still hold to
the notion that each source declaration produces a unique type identity.
That's the notion most important to a software engineer: knowing that
there is exactly one source location that governs accesses to any
given strong data type.  All the functional variations are expressed
by specializing the enclosing design components around this source
location.  Finally instantiating them doesn't alter function or source
ancestry - it only fills in object names for all the copies of these
functionally unique specializations.

Surely in the few cases where instance-specificity might be desired,
some further syntactic specification could be applied whose effect
would be to capture the module/interface instance_identity into a
type's matching criteria.  Maybe "unique struct { ... }" ?

Greg Jaxon

BIG disclaimer:  This is really just personal opinion at this point.
This belonged on the agenda several years back - and I'm sure it was
discussed then.  I regret having been unable then to penetrate the
LRM verbiage enough to make this point clearly.  I don't think it's
too late to make it now.


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Tue Sep 4 20:57:13 2007

This archive was generated by hypermail 2.1.8 : Tue Sep 04 2007 - 20:57:35 PDT