Language Change Specification for Environment API

LCS Number: LCS-2016-006d
Version: 1 {06-Feb-2017}
2 {22-Feb-2017}
3 {02-Mar-2017}
4 {06-Mar-2017}
Date: 06-Mar-2017
Status: Voting
Author: Patrick Lehmann
Email: Main.PatrickLehmann
Source Doc:  
Summary: Allow access to system environment variables and conditional analysis identifiers.
Dependencies: LCS-2016-061

Voting Results: Cast your votes here

Yes:

  1. Yann Guidon - 2017-02-06 - ver 1
  2. Jakko Verhallen- 2017-02-07 - ver 1, but considering the comments
  3. Patrick Lehmann - 2017-02-06 - ver 4
  4. %(USERSIG(SteveGrout - 2017-02-06)% - ver 4

No:

  1. Thomas Preusser - 2017-02-07 - ver 1 - too hacky. Please, see comment and alternate proposal LCS 006e.
  2. Martin Zabel - 2017-03-07 ver 4 - Some functions still have undefined behavior and I also dislike this version of the LCS, both is described in my comment of 2017-03-07.

Abstain:

  1. Ryan Hinton - 2017-02-10 Prefer LCS 006e.
  2. Brent Hayhoe - 2017-02-16 Version 1 - Abstain due to lack of personal time for review.
  3. Rob Gaddi - 2017-02-21 Prefer LCS 006e.

Style Notes

Changes are shown in red font.
Deletions are crossed out.
Editing or reviewing notes in green font.

Reviewing Notes

Version 1:
A pair of procedures (ENV_OPEN, ENV_CLOSE) is provided to read the host environment of a tool. All conditional compilation identifiers
and their values are provided as well as a list of available environment variables. An environment variable can be queried by ENV_GETVALUE.

Version 2:

Version 3:

  • Made all conditional analysis identifiers a record element in a deferred constant.
  • Created function and procedure overloads to address different use cases

Version 4:

  • Specified returned values if operation fails

Details of Language Change

16.5 Standard environment package

16.5.1 General [NEW headline level]

Package ENV contains declarations that provide a VHDL interface to the host environment.

package ENV is
  procedure STOP (STATUS: INTEGER);
  procedure STOP;
  procedure FINISH (STATUS: INTEGER);
  procedure FINISH;
 
  function RESOLUTION_LIMIT return DELAY_LENGTH;

  [... LCS-2016-011 ...]

  [... LCS-2016-006c ...]

  type ENV_VARIABLE_NAMES is access LINE_VECTOR;
  -- The predefined operations for this type are as follows:
  -- function"=" (anonymous, anonymous: ENV_VARIABLE_NAMES) return BOOLEAN;
  -- function"/=" (anonymous, anonymous: ENV_VARIABLE_NAMES) return BOOLEAN;
  -- procedure DEALLOCATE (P: inout ENV_VARIABLE_NAMES);
 
  type COND_ANALYSIS_IDS is access LINE_VECTOR;
  -- The predefined operations for this type are as follows:
  -- function"=" (anonymous, anonymous: COND_ANALYSIS_IDS) return BOOLEAN;
  -- function"/=" (anonymous, anonymous: COND_ANALYSIS_IDS) return BOOLEAN;
  -- procedure DEALLOCATE (P: inout COND_ANALYSIS_IDS);

  type ENVIRONMENT is record
    -- Resolution_Limit : DELAY_LENGTH;         -- 
    Variables        : ENV_VARIABLE_NAMES;   -- list of pointers to environment variable names
    Identifiers      : COND_ANALYSIS_IDS;    -- list of pointers to conditional analysis identifiers
  end record;

  procedure       ENV_OPEN(Env : out ENVIRONMENT);
  impure function ENV_OPEN return ENVIRONMENT;
  procedure       ENV_CLOSE(Names : in ENVIRONMENT);        -- deallocate all internal access values
 
  procedure       ENV_GETVARIABLE(Value : out LINE; Name : in STRING; Good : out BOOLEAN);
  impure function ENV_GETVARIABLE(Name : in STRING; Good : out BOOLEAN) return LINE;
  impure function ENV_GETVARIABLE(Name : in STRING) return LINE;
  impure function ENV_GETVARIABLE(Name : in STRING; Good : out BOOLEAN) return STRING;
  impure function ENV_GETVARIABLE(Name : in STRING) return STRING;
 
  procedure       ENV_GETIDENTIFIER(Value : out LINE; Name : in STRING; Good : out BOOLEAN);
  impure function ENV_GETIDENTIFIER(Name : in STRING; Good : out BOOLEAN) return LINE;
  impure function ENV_GETIDENTIFIER(Name : in STRING) return LINE;
  impure function ENV_GETIDENTIFIER(Name : in STRING; Good : out BOOLEAN) return STRING;
  impure function ENV_GETIDENTIFIER(Name : in STRING) return STRING;
 
  type CONDITIONAL_ANALYSIS_IDENTIFIER is record
    VHDL_Version : STRING;               -- see 24.2 Conditional Analysis Tool Directives
              
    Tool_Type    : STRING;               -- see 24.2 Conditional Analysis Tool Directives
    Tool_Vendor  : STRING;               -- see 24.2 Conditional Analysis Tool Directives
    Tool_Name    : STRING;               -- see 24.2 Conditional Analysis Tool Directives
    Tool_Edition : STRING;               -- see 24.2 Conditional Analysis Tool Directives
    Tool_Version : STRING;               -- see 24.2 Conditional Analysis Tool Directives
  end record;
 
  constant COND_ANALYSIS_ID : CONDITIONAL_ANALYSIS_IDENTIFIER;
end package ENV;

[Editor note: Three notes ...]

16.5.5 System Environment and Conditional Analysis Identifier API [NEW]

The procedure ENV_OPEN, with parameter Env, returns a record of type ENVIRONMENT, which describes the current tool environment. The record member Variables
references an array of access values (LINE_VECTOR) representing the names of each available environment variable.

The impure function ENV_OPEN, implements the same behavior as the procedure ENV_OPEN. The procedure's output parameter Env of type ENVIRONMENT
in the return value of the function.

The procedure ENV_CLOSE, with parameter Env, deallocated objects allocated by ENV_OPEN.

The procedure ENV_GETVARIABLE, with parameters Value, Name and Good, returns the value of an environment variable from the host environment as a LINE value. If
the environment variable denoted by Name is not available in the host environment, an error is signaled by setting the status parameter Good to FALSE, otherwise TRUE. The value of Value is null if the operation is not successful.

The impure function ENV_GETVARIABLE, with parameters Name and Good returning type LINE, implements the same behavior as the procedure ENV_GETVARIABLE, with parameters
Value, Name and Good. The procedure's output parameter Value of type LINE in the return value of the function.

The impure function ENV_GETVARIABLE, with parameter Name returning type LINE, implements the same behavior as the impure function ENV_GETVARIABLE, with parameters
Name and Good returning type LINE. It is an error if Name denotes an environment variable, that doesn't exist in the host environment.

The overloaded impure function ENV_GETVARIABLE, with parameters Name and Good returning type STRING, implements the same behavior as the impure function ENV_GETVARIABLE,
with parameters Name and Good returning type LINE. The function returns the designated object: an object of type STRING.

The impure function ENV_GETVARIABLE, with parameter Name returning type STRING, implements the same behavior as the impure function ENV_GETVARIABLE, with parameters
Name and Good returning type STRING. It is an error if Name denotes an environment variable, that doesn't exist in the host environment.

The procedure ENV_GETIDENTIFIER, with parameters Value, Name and Good, returns the value of a conditional analysis identifier from the tool environment as a LINE value. If
the identifier denoted by Name is not available in the tool environment, an error is signaled by setting the status parameter Good to FALSE, otherwise TRUE. The value of Value is null if the operation is not successful.

The impure function ENV_GETIDENTIFIER, with parameters Name and Good returning type LINE, implements the same behavior as the procedure ENV_GETIDENTIFIER, with parameters
Value, Name and Good. The procedure's output parameter Value of type LINE in the return value of the function.

The impure function ENV_GETIDENTIFIER, with parameter Name returning type LINE, implements the same behavior as the impure function ENV_GETIDENTIFIER, with parameters
Name and Good returning type LINE. It is an error if Name denotes an identifier, that doesn't exist in the tool environment.

The overloaded impure function ENV_GETIDENTIFIER, with parameters Name and Good returning type STRING, implements the same behavior as the impure function ENV_GETIDENTIFIER,
with parameters Name and Good returning type LINE. The function returns the designated object: an object of type STRING.

The impure function ENV_GETIDENTIFIER, with parameter Name returning type STRING, implements the same behavior as the impure function ENV_GETIDENTIFIER, with parameters
Name and Good returning type STRING. It is an error if Name denotes an identifier, that doesn't exist in the tool environment.

The record type CONDITIONAL_ANALYSIS_IDENTIFIER describes the set of available conditional analysis identifiers. The record shall contain all identifiers
as defined in 24.2 Conditional Analysis Tool Directives as well as all tool and user defined identifiers. Each identifier is represented by a corresponding record
element of the same name. Each element is a STRING object holding the associated value of an identifier. None of these record elements shall be a null value.

A deferred constant COND_ANALYSIS_ID of type CONDITIONAL_ANALYSIS_IDENTIFIER is defined in the package. It's content is assigned in the tool dependent package body.

Comments

Version 1

For ENV_GETVALUE, how do I pick the appropriate length for Value? How does the procedure indicate the size of the object? See Sread. It returns a length value in this situation.

Why do I need anything other than ENV_GETVALUE? Why do I want to get the entire object as a data structure?

-- Jim Lewis - 2017-02-06

Or even go crazy and have:

procedure ENV_GETVALUE(Name : in STRING; Value : out STRING; Good : out BOOLEAN);
impure function ENV_GETVALUE(Name : in STRING) return STRING;

But I can't see a scenario where I need anything more complex than that from VHDL.

-- Rob Gaddi - 2017-02-06

For the procedure, I think it needs STRLEN (like sread) rather than Good. Like sread, if there is an error, STRLEN = 0.

procedure ENV_GETVALUE(Name : in STRING; Value : out STRING; STRLEN : out Natural);

I agree with Rob about the procedure though

-- Jim Lewis - 2017-02-06

So I need to return either a size or a LINE parameter, right?

Some users demanded that the values for the conditional compilation should be available in code too. By adding all the identifiers from 24.2 this demand is fulfilled.

I think a user should have access to all available environment variable names. If I start to use such a feature in a language, I get quickly to the point that I can't list all available variables.

-- Patrick Lehmann - 2017-02-07

IMHO this appears too big a hack right now. Too many compromises to make it work with the current version of VHDL. The record ENVIRONMENT appears especially obscure to me as it is an artificial join of the identifiers for conditional compilation (CC) and the OS environment variables both delivered through different abstractions. Some kind of a map abstraction would be appropriate in both cases so as to warrant maximum flexibility. LCS 061 allows to have a CC identifier set extended by the tool or the user. The current approach leaves those inaccessible. With what we have in VHDL, the map abstraction is best represented by a function. So, I would expect a core set of functions like this:

function GETENV(name : in string) return string;      -- would have to return an empty string for a name not defined in the environment

OR closely following the POSIX function:

function GETENV(name : in string) return line;      -- returns null for a name not defined in the environment

AND, a similar access to CC identifiers:

function GETDEF(name : in string) return string/line;

Optionally, you might want to consider to give access to a list of defined names. I think functions returning a line_vector would be most appropriate:

function GETENV_NAMES return line_vector;
function GETDEF_NAMES return line_vector;

-- Thomas Preusser - 2017-02-07

"For the procedure, I think it needs STRLEN (like sread) rather than Good. Like sread, if there is an error, STRLEN = 0. " But what if the variable exists, and is empty? e.g. setenv MYLIST "" I think the STRLEN should be -1 in case of an error, 0 in case of empty. I would vote definately YES on the impure function.

-- Jakko Verhallen - 2017-02-07

WRT the names defined by conditional compilation, why not create a set of similarly named deferred constants here in the package std.env?

-- Jim Lewis - 2017-02-10

@Jim: Introducing such constants may help for the standard identifiers, which Patrick also included in this environment record. Both approaches are not really suitable to cope with tool- and user-defined identifiers. At least I would avoid having a record type or set of pre-defined constants that are adjusted in each run to reflect the currently defined set of conditional compilation identifiers.

IMHO, a lookup mechanism just as used by Patrick for the environment variables should be provided for conditional compilation identifiers as well. This:

  • keeps them in their own name space,
  • makes them easily accessible from VHDL code, and
  • is fully flexible with respect to tool- and user-defined identifiers.

See LCS 006e for an alternative pursuing this approach.

-- Thomas Preusser - 2017-02-10

It would be polite to get a chance to address the comments and have some time to rewrite the LCS.

-- Patrick Lehmann - 2017-02-11

string return values are awkward to work with. It would need to be called with a corresponding call to justify to be even usable. Otherwise, the only thing one can do with it is use the return value in an expression.

We need some indication to size the string return value. see SREAD.

-- Jim Lewis - 2017-02-14

Version 4

These functions still have undefined behavior:

impure function ENV_GETVARIABLE(Name : in STRING; Good : out BOOLEAN) return STRING;
impure function ENV_GETIDENTIFIER(Name : in STRING; Good : out BOOLEAN) return STRING;

The definition for ENV_GETVARIABLE is (ENV_GETIDENTIFIER is similar):

The overloaded impure function ENV_GETVARIABLE, with parameters Name and Good returning type STRING, implements the same behavior as the impure function ENV_GETVARIABLE, with parameters Name and Good returning type LINE. The function returns the designated object: an object of type STRING.

But, if the environment variable denoted by Name is not availbale in the host environment, then the function ENV_GETVARIABLE(Name : in STRING; Good : out BOOLEAN) return LINE; returns a null access value. Thus, the function above cannot return the designated object (as already expressed in my private e-mail to you before). There are two options here:

  1. It is an error if Name denotes an environment variable, that doesn't exist in the host environment. (Like it is done for the function ENV_GETVARIABLE(Name : in STRING) return STRING;.)
  2. Return a null string "", and check for existence using Good.

Why I dislike this version of the LCS:

1) For each namespace (environment variables and identifiers), this LCS defines 5 functions where only 2 functions are required. For example, the procedure call

constant Name : string := "test";
variable Value : line;
variable Good : boolean;
...
ENV_GETVARIABLE(Value, Name, Good);

could be simply replaced by:

Value := ENV_GETVARIABLE(Name, Good);

And this call could be even more simplified to:

Value := ENV_GETVARIABLE(Name);

because the out parameter Good is never needed. Whether the variable exists in the host environment or not could be simply determined by the returned Value:

Value := ENV_GETVARIABLE(Name);
if Value = null then
    report "Environment variable does not exist in host environment." severity error;
elsif Value.all = "" then
    report "Environment variable is defined but empty.";
else
    report "Environment variable has value: " & Value.all;
end if;

The discussion for the function ENV_GETVARIABLE(Name : in STRING; Good : out BOOLEAN) return STRING;" depends on how the undefined behavior is solved:

  1. If an error is raised anyway, then Good needs not to be checked and one can simply call the function ENV_GETVARIABLE(Name : in STRING) return STRING;".
  2. If a null string is returned, then Good must be checked after the returned value is used in an expression. I expect less readable code here.

The function ENV_GETVARIABLE(Name : in STRING) return STRING; is fine, especially, if the (synthesis) tool does not support access types.

Thus, the only required functions are:

impure function ENV_GETVARIABLE(Name : in STRING) return LINE;
impure function ENV_GETVARIABLE(Name : in STRING) return STRING;

Same discussion applies to ENV_GETIDENTIFIER.

2) Why should there be a function ENV_OPEN and a procedure ENV_OEPN?

3) Why are there two types ENV_VARIABLE_NAMES and COND_ANALYSIS_IDS representing both an access type of LINE_VECTOR?

4) According to the LCS text, the type ENVIRONMENT does describe the current tool environment. But why does it contain only the identifiers and not also the values?

Added later:

5) I find writing something like if COND_ANALYSIS_ID.Tool_Type = "SIMULATION" then just too long. The prefix COND_ANALYSIS_ID is also hard to remember. I prefer LCS 006f instead.

-- Martin Zabel - 2017-03-07

Topic revision: r28 - 2020-02-17 - 15:34:40 - JimLewis
 
Copyright © 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback