2
\$\begingroup\$

Is there a syntax where one can use a record type in a PORT declaration, but specify that certain members of the record are IN or OUT?

I could be asking an XY problem here; so the overall picture that I would like to create an entity that has a single record for all of its ports. That way, maintaining at my TOP will be a lot cleaner. However, some ports are input and some are output; and I have no idea how to specify which member of the signal would be IN or OUT. I could break the record members out individually; but then how would the entity know that its port is actually of type record? The whole point is to use the record type to ease signal assignments; so breaking them out defeats that purpose.

I have tried just assigning the record as an INOUT; but simulation breaks because it doesn't think that certain signals (specifically IN) are being driven by anything (which my testbench definitely is assigning values).

So I am at a loss here. Is the only option to break my record into IN and OUT sub records and carry both around??

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

It depends on if it is Design or Verification. For Design until your vendors support VHDL-2019 interfaces you need one record for in and one record for out.

For verification is better with VHDL-2019 interfaces, but you can take liberties with the resolution functions of your records. In Open Source VHDL Verification Methodology (OSVVM), we use maximum resolution function to resolve record elements.

Step 1: Record + Elements with Resolved Types OSVVM interfaces use records whose elements are a resolved type from the OSVVM package ResolutionPkg.

type AddressBusMasterTransactionRecType is record
  Rdy             : bit_max ;
  Ack             : bit_max ;
  Address         : std_logic_vector_max ;
  AddrWidth       : integer_max ;
  DataToModel     : std_logic_vector_max ;
  DataFromModel   : std_logic_vector_max ;
  . . .
end record AddressBusMasterTransactionRecType ;

Types in ResolutionPkg use “maximum” as a resolution function and add the suffix “_max” to the type names. Maximum resolution picks the largest value driven on each element of signal object that has multiple drivers. The largest value is the right most value of a type (‘-‘ for std_ulogic). This works in conjunction with the left most value being the smallest and the default value for an object of that type.

ResolutionPkg provides the following (as subtypes): std_logic_max, std_logic_vector_max, unsigned_max, signed_max, bit_max, bit_vector_max, integer_max, integer_vector_max, time_max, time_vector_max, real_max, real_vector_max, character_max, string_max, boolean_max, and boolean_vector_max.

Step 2: Use Mode InOut on Interfaces If all of the elements of the record are a type from ResolutionPkg, then the interface signal can have mode InOut and nothing more is needed. If an element of the record is not driven, then the value it contributes is the left most value of the type – which again is the smallest value.

entity Axi4LiteMaster is
  port (
    -- Globals
    Clk         : in ;
    nReset      : in ;  

    -- Testbench Transaction Interface
    TransRec    : inout AddressBusMasterTransactionRecType ;

    -- AxiLite Interface
    AxiLiteBus  : inout Axi4LiteRecType  -- **
  ) ;
end entity Axi4LiteMaster ;

On the OSVVM Axi4Master, we handle the AxiBus using std_logic_1164 types instead. In this case, all elements of Axi4 that are not directly driven by Axi4Master are driven to ‘Z’ to resolve them.

Step 3: Instantiate the Design Exactly what you do with an ordinary type. If you use unconstrained elements, you will need to add range constraints to the signals that use the record type, but that does not impact the usage at the interface (port map).

Step 4: Work Arounds Not all simulators support the VHDL-2008 method of applying an element resolution function to an array (as done by vector subtypes of the form “_max”). As a result, ResolutionPkg provides a type of the form “_max_c”. It is simply an array whose element is of the form “_max”.

OSVVM verification components all use “_max_c” because it allows our models to work on a wider range of simulators. There is a small cost. Since types like std_logic_vector_max_c are types, when assigning between them and std_logic_vector, a type conversion, such as the following are required.

-- assigning a std_logic_vector to a std_logic_vector_max_c
TransactionRec.DataToModel  <= std_logic_vector_max_c(Data) ;

-- assigning a std_logic_vector_max_c to a std_logic_vector
ReadData := std_logic_vector(TransactionRec.DataFromModel) ;

Subtypes like std_logic_vector_max and std_logic_vector do not require a conversion function since they are both subtypes of std_ulogic_vector (since VHDL-2008), and hence, they convert automatically.

If you are interested in previewing VHDL-2019 interfaces, see my article at https://osvvm.org/archives/1668 that covers both of these topics.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.