Deferred Shared Variables

Proposal Details

Current Situation

Defined in the analysis of VHDL2008 IR2119.

Requirement

Provides a methodology or mechanism that will permit a shared variable to be defined in the same package as the protected type.

Use Cases

See also 'Arguments For'.

Use Case: Shared Variable in Multiple Packages (Brent H)

My verification test benches often take the form as below:

               -----
  -------     |     |     -------
 | MDL_A |<-->|     |<-->| MDL_C |
  -------     |     |     -------
              | DUT |
  -------     |     |       -------
 | MDL_B |<-->|     |      | CNTRL |
  -------     |     |       -------
               -----

The models can be quite simple I/O functions to drive the DUT or quite complex BFMs.

The controller block has no physical connections to the DUT or models. It controls events via global signals and uses shared variables to set up the outputs of the models.

The shared variables are declared in packages belonging to each model, i.e. on a per model basis and requiring two packages per model.

So for the first protected type package might be:

  TYPE op_type_r IS
    RECORD
      output1_l : Std_Logic;
      output2_l : Std_Logic_Vector(2 DOWNTO 0);
      output3_l : Std_Logic;

    END RECORD op_type_r;

  TYPE op_type_pr IS
    PROTECTED

      IMPURE FUNCTION value_if
        RETURN op_type_r;

      PROCEDURE set_p (
        op_type_ri : op_type_r
        );

    END PROTECTED op_type_pr;

and then in the second package:

  -- initialize to value
  SHARED
    VARIABLE  op_init_rsv         : op_type_pr;

This approach allows me to initialize a models outputs, alter them during simulation or set them into error conditions in order to stimulate the DUT.

My problem is two packages per model instead of one, with the extra work involved in maintenance and the obvious difficulties in code comprehension with the declarations split across two files.

Use Case: Shared Variable References in Package (Jim L)

Once declared, shared variables can also be used in a package. In the following, the shared variable RV (randomization object) is used to randomly select an initialization for the signals GlobalInt and GlobalSlv.

 
  shared variable RV : RandomPType ;
  signal GlobalInt : integer := RV.RandInt(0, 255);
  signal GlobalSlv : std_logic_vector(1 downto 1) := RV.RandSlv(0,1,1) ;

Arguments FOR

a.

In my verification test benches, I often have shared variables defined on a model by model basis. This leads to each model requiring two packages; one for the shared variables and one for the protected types. It would simplify maintenance having one single package. My controlling block tends to be disconnected (physically) from the test bench, is driven from a TCL script and controls the simulation via shared variables and global signals. - BAH

Test Model Control Details:

The global signals provide simulation event (time) control of the various models and the shared variables are used to control their functionality.

My global signals are typically enumerated types e.g. (init_e, run_e, pause_e, end_e) used to control the status of the model.

My shared variables are normally record types of the model's output signals, used to control their values, with corresponding matching records of boolean types setting stuck-at and/or invert status of the respective signals. These boolean records allow for error conditions to be set on the model's outputs.

These shared variable formats are, by the nature of their record structure, specific to each model, which then require a package for their protected type definitions... thus two packages per model as opposed to one. - BAH

b.

It is something that new users would automatically think should be supported. - BAH

Implementation Candidates

Candidate 1: Deferred Shared Variables (Brent H)

Allow a shared variable to be declared in the same package as a protected type by providing a mechanism to defer the elaboration of the 'shared variable' until after the 'protected type body' has been elaborated (in the same package).

Add a new keyword 'deferred' to indicate that the 'shared variable' elaboration needs to be deferred until the 'package body' is elaborated.

Candidate 1: Code Examples

  package MY_PACKAGE is
    ... 
    type MY_PROTECTED_TYPE is 
      protected
        ... 
      end protected MY_PROTECTED_TYPE;

    shared variable MY_VARIABLE : MY_PROTECTED_TYPE deferred; 

  end package MY_PACKAGE;


  package body MY_PACKAGE is
    ... 
    type MY_PROTECTED_TYPE is 
      protected body
        ... 
      end protected body MY_PROTECTED_TYPE;

    shared variable MY_VARIABLE : MY_PROTECTED_TYPE; 

  end package body MY_PACKAGE;

Candidate 1: Other Syntax Considerations

As one of the aims of the group is to reduce the amount of proposed new keywords, the 'deferred' keyword could possibly be replaced by the 'postponed' keyword.

(However, to me, this doesn't seem to have the right syntactical sound and I would favour sticking with the 'deferred' keyword. - BAH)

The 'deferred' keyword could also be an additional option to the deferred 'constant' definition for uniformity.

Candidate 1: Global SIgnal Initial Values

The 'deferred' keyword could also be used to defer a (global) 'signal' initial value assignment which uses either a deferred 'shared variable' access method, a deferred 'constant' value, or a 'function' return value.

Candidate 1: Arguments AGAINST

This seems to be a significant change to VHDL's elaboration model.

Candidate 1: Language Concerns (CliffordWalinsky)

  1. I don't understand the utility of the new deferred (or even postponed) keyword. If the keyword is missing, that presumably means a shared variable of the protected type cannot be defined in the package header. Certainly, a compiler can check for the presence of a declared shared variable and the presence of the deferred keyword in the type definition. Except, I don't understand why one wouldn't want to always use the deferred keyword, once issues concerning elaboration of a shared variable within the body of the package have been addressed.

<Brent Hayhoe> For a constant, the omission of the expression assignment is normally defined as an error condition, except when used in the declaritive part of a package. The omission here implies the constant as deferred and it is then assigned during elaboration of the package body. The main advantage of this is the abilty to use functions, defined in the same package, within the expression assjgnment of the constant.

If we were to declare a global signal in a package and assign it an initial value using a function within the expression, without the 'deferred' keyword there is no way for the compiler to imply its deferred status. The omission of its initial value expression is quite valid and cannot be used to imply a deferred status.

For a shared variable, although we could imply a deferred status by the fact that its protected type is defined in the same package, it would seem to put more effort onto the compiler function rather than require the new 'deferred' keyword to explicitly define its deferrred status. </Brent Hayhoe>

  1. The language standard should be expanded to explicitly state that elaboration of a protected type body shall occur during elaboration of the package body that contains it. Further, it needs to be explicitly stated that a design is erroneous if elaboration of a protected type body refers to a deferred constant or other shared variable that has not yet been elaborated.

Candidate 2: Allow Protected Type Bodies in Package Declaration Region (Jim L)

Allow a protected type body (and perhaps a subprogram body) to be included in a package declarative area. As a result, a shared variable could then be declared immediately after the protected type body - in an identical fashion to its use in an architecture declaration region. This use model would also make it similar to how other languages use classes.

The protected type body then would be the syntax that separates the public space of the protected type from the private space.

Arguments Against

Needs use cases not "Arguments For", so really cannot judge how important this is.

Email Reflector Comments

From: JimLewis (Mon Dec 17 2012 - 14:33:23 PST)

A use case that illustrates what your are trying to do and why would be helpful.

I am using protected types quite extensively, but I suspect that I am using them for a different purpose than you. Most of my shared variable declarations I use are private to an instance of a design and I declare them in the architecture declaration region.

Are you putting the shared variable declarations in a package to allow different instances (perhaps of the same design) to share a data structure?

Currently I am more limited by not allowing shared variables on interfaces and not allowing arrays of shared variables. I also need generics on protected types so I can effect an initializer.

From: MartinThompson (Tue Dec 18 2012 - 01:32:30 PST)

I read your DeferredSharedVariables page yesterday, wasn't aware of the history, so thanks for pointing me to that.

As with Jim, my use of shared variables is limited to "local" instances, so I haven't come across the problem - I would also appreciate an example of when you find this useful.

My immediate thought on reading your description was that, rather than introduce a 'deferment', can we not change things so that the "expected" behaviour actually happens? Is there a good reason for not being able to declare a shared variable in the same region as its type definition?

From: JonathanBromley (Tue Dec 18 2012 - 01:48:39 PST)

Brief comment from the sidelines by an interested but inactive observer:

I don't have as much experience in using protected types as I do with other kinds of OO-style programming, so I may be off track here, but... If a package provides some protected type as a service to the rest of your code, there may well be situations where the same package also should provide some "specimen" instances of that type - maybe as templates that help in the construction of new instances, maybe as predefined globally accessible objects (I could imagine that being useful, for example, for an objections mechanism).

It does seem perverse that you can't actually create one of the shared variables inside the package that defines their type. For example, in SystemVerilog I would find it very troublesome if I could not declare a package-level variable of a class type in the same package that defines the class.

From: JimLewis (Tue Dec 18 2012 - 09:25:29 PST)

One thing that differentiates VHDL from other languages is the division between protected type declaration and body. In addition within a package, the protected type body must be in the package body. Hence, in the package declarative region the protected type is not yet fully defined.

In the current language, I can make the following shared variable declaration and then use it. Should I be able to do this with "deferred" shared variables or should it be illegal? This would mean then that the elaboration of anything that references the shared variable also needs to be deferred.

   shared
      variable RV        : RandomPType ;
   signal      GlobalInt : integer                       := RV.RandInt(0, 255);
   signal      GlobalSlv : std_logic_vector(1 downto 1)  := RV.RandSlv(0,1,1) ;

The reason we need to see use models is that there may be less complicated solutions that acceptably solve the problem. What is the real problem? Having to put the shared variable in a different package or having more than one package reference.

One alternate solution could to allow a protected type body (and perhaps a subprogram body) to be included in a package declarative area. This then would make a shared variable use model identical to an architecture.

If the problem is having more than one package reference, then don't forget about the VHDL-2008 context clause.

From: Brent Hayhoe (Tue Dec 18 2012 - 09:25:29 PST)

I have put a few lines on the proposal page trying to explain how I use shared variables and the problems I have.

Looking at your example (below)above at first confused me, until I realised what you are doing (I think).

I presume that you are using the method sub-programs from the protected type to set the variable and use it to assign the initial values to the global signals.

I assume that if you had used functions and constants to achieve this, then the constants would have had to be deferred?

However, your point is well made and perhaps this shows that we may need to allow (global) signals to be deferrable as well? This would sync well into the language I think.

As to you suggestion whether we allow protected type bodies into the package declarative part, I do not know, but my gut instinct is probably no. However, I have to defer (pun?) to the language and compiler experts amongst us on this point.

From: TristanGingold - 2016-07-12

The example from Jim L is clearly invalid: RandInt cannot be called before being elaborated. One way to fix that (as suggested by Jim L) would be to allow protected bodies in package specification. That breaks a fundamental software engineering rule (spec vs impl), but why not.

I don't really like the addition of deferred reserved word. Furthermore, deferred declarations can create a lot of elaboration issue. What about allowing statements in a package body:

package body pkg is
   ...
begin
   --  Statements executed during elaboration of the package body.
   my_var := xxx;
end pkg;

That doesn't work with signal but I think this is not an important restriction.

Supporters

-- Brent Hayhoe - 2012-12-16

-- PatrickLehmann - 2016-07-18

Analysis

This proposal was discussed in the 2016 May 26th meeting under item 81 of the ranked proposals spreadsheet for VHDL201x.

The requirement has similarities to deferred constants.

At least one HDL simulator vendor supports this (currently) non-standard functionality with a tool compiler switch, i.e. to solve the problem of a shared variable with its protected type in the same package.

The meeting decided that it would be better syntactically if the new reserved word deferred appeared at the beginning of the statement becoming more like an object class modifier.

The new reserved word deferred can now be used as an alternative to omitting the value assignment in a constant declaration and also for signal declarations to allow the same delayed value assignment functionality for their initial values.

Deferred Constants

If we wish to define a function plus a constant in the same package and in so doing we want to use the function to define the value of the constant then the value cannot be assigned in the package declaration because at this point in the analysis phase it knows nothing about the body of the function.

   package my_package is
      function my_function(a, b : integer) return my_signed;
      constant my_constant : my_signed;   -- deferred constant
   end package my_package;

If we just move the constant declaration to the package body (after the function body) the problem is resolved. However, the constant cannot now be made visible (by a use statement) outside the scope of the package.

In order to overcome this problem, the value assignment of the constant in the package declaration is omitted and this defines the object as a deferred constant giving visibility to the constant assigned in the package body.

   package body my_package is
      function my_function(a, b : integer) return my_signed is
      begin
         ...
      end function my_function;
      constant my_constant : my_signed := my_function(1, 2);   -- constant value assigned
   end package my_package;

The constant declaration is repeated in the package body (after the function body) with the value assignment included.

Deferred Shared Variables

If we wish to define a protected type plus a shared variable in the same package there is a similar problem.

The shared variable cannot be declared in the package declaration because at this point in the analysis phase it knows nothing about the body of the protected type and its methods and local variable(s), only the declaration of the methods.

   package my_package is
      type my_type is protected
         function value return my_signed;
         procedure set(value : my_signed);
      end protected my_type;
      deferred shared
         variable my_variable : my_type;   -- deferred shared variable
   end package my_package;

If we just move the shared variable declaration to the package body (after the protected type body) the problem is resolved. However, the shared variable cannot now be made visible (by a use statement) outside the scope of the package.

The work-around is to declare the shared variable in a second package which 'uses' this package.

   package body my_package is
      type my_type is protected body
         variable local : my_signed;
         function value return my_signed is
         begin
            ;
         end function value;
         procedure set(value : my_signed);
         begin
            ;
         end procedure set;
      end protected my_type;
      shared
         variable my_variable : my_type;   -- analysed shared variable
   end package my_package;

A better solution to overcome this problem is to delay the analysis of the shared variable to the body of the package, but unlike deferred constant a new keyword - deferred - is added after the subtype indication giving visibility to the shared variable declared in the package body.

Deferred Signals

If we wish to define a function plus a global signal in the same package and in so doing we want to use the function to initialize the value of the global signal then this now becomes possible.

   package my_package is
      function my_function(a, b : integer) return my_signed;
      deferred
         signal my_global : my_signed;   -- deferred global signal
   end package my_package;
We can now delay the analysis of the global signal to the body of the package using the new keyword - deferred.
   package body my_package is
      function my_function(a, b : integer) return my_signed is
      begin
         ...
      end function my_function;
      signal my_global : my_signed := my_function(1, 2); -- global signal initial
   end package my_package;                               --         value defined

BNF Productions

constant_declaration ::=
     constant identifier_list : subtype_indication [ := expression ] ;
   | deferred constant identifier_list : subtype_indication ;
variable_declaration ::=
     variable identifier_list : subtype_indication [ := expression ] ;
   | [ deferred ] shared variable identifier_list : protected_subtype_indication ;
signal_declaration ::=
     signal identifier_list : subtype_indication [ signal_kind ] [ := expression ] ;
   | deferred signal identifier_list : subtype_indication [ signal_kind ] ;

LCS

Link to Deferred Shared Variables LCS-2016-080.

Topic revision: r33 - 2016-11-28 - 11:25:48 - BrentHahoe
 
Copyright © 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback