RE: [vhdl-200x] Record slices (branched from Directional records proposal)

From: <>
Date: Thu Jul 19 2012 - 11:05:52 PDT

You and Andy are right. So I don't see that you can do much with record slices other than declare a subtype or possibly use it in the directional records proposal. Can anyone think of another use?


- Ryan


From: [] On Behalf Of
Sent: Thursday, July 19, 2012 6:03 AM
Subject: Re: [vhdl-200x] Record slices (branched from Directional records proposal)


Right now, I believe VHDL has polymorphism but not dynamic polymorphism. So don't you run into a brick wall with

for field in misc'fields loop

    write(ln, obj.field);

? In VHDL, the types need to be statically determinable. The type of obj.field would be dynamic, would it not?


John A wrote: -----

To: <>
Sent by:
Date: 07/18/2012 06:26PM
Subject: Re: [vhdl-200x] Record slices (branched from Directional records proposal)

You're right, it would be hard to create an expression with these dynamically-accessed fields, but VHDL has rather capable polymorphism. Here's a reasonable example.


  -- record containing fields with disparate types

  type misc is record

    int : integer;

    float : real;

    snum : signed(7 downto 0);

  end record misc;


  -- object of this type

  signal obj : misc;


  -- loop over fields and write to a single line in a LINE variable

  for field in misc'fields loop

    write(ln, obj.field);

  end loop;

  writeline(F, ln);


This could work because the write procedure is overloaded for all of the types in the record. If the O.P. overloads his pack() and unpack() subprograms appropriately, it seems like a similar construction will work for him. Interestingly, the currently language allows the OTHERS choice in aggregates despite the typical case where it doesn't work. And I've never had a problem with it in my code because it doesn't make any sense to use it in the wrong way.


This can be accomplished by extending the language to implicitly declare an (anonymous) enumerated type whose values are the record type field names in order. Then the record field access (dot syntax) becomes very similar to an array lookup. In LRM parlance, it acts like an indexed name instead of a selected name. Existing code simply uses the enumeration literals everywhere, while the code above uses a constant (the loop index) of the enumeration type. We could add record type attributes T'FIELDS to provide a range containing the field names, and T'FIELDS_TYPE to provide the enumerated type for the field names. This is the only sane approach I've yet seen to this proposal.


I don't see any backward compatibility issues with this interpretation -- in particular with visibility, homographs, and overloading. But I haven't fully researched the implications (esp. indexed versus selected name). And I'm still not sure I like it, but I can't seem to find any compelling reason against it.


Are there any other good use cases? So far this has been suggested for use with directional ports (more comments coming on that topic) and in FOR loops utilizing polymorphism.




- Ryan


From: [] On Behalf Of Peter Flake
Sent: Wednesday, July 18, 2012 8:31 AM
Subject: RE: EXTERNAL: Re: [vhdl-200x] Directional records proposal


I think that the problem with a language-native way is that there is no dynamic typing. Each field can have a different data type, and so there is no expression type that could represent any field in the record. An alternative is to use the VHPI.




From: [] On Behalf Of Huffman, Nathanael D (GE Healthcare)
Sent: 17 July 2012 23:02
Subject: RE: EXTERNAL: Re: [vhdl-200x] Directional records proposal


I use record types as command and status registers. In order to make this useful I have a tcl script that generates overloaded pack() and unpack() functions that convert the records into slvs for interfacing with a databus for the processor. I think the ability to loop through record elements could allow a language-native way of doing this rather than using a pre-processor to generate these functions. The individual functions would still be required due to the different types for each register, but they could be coded in a generic way by looping through the record and concatenating rather than the “hard-coded” method of assigning record fields to slices of the returned vector.




From: [] On Behalf Of Brent Hayhoe
Sent: Tuesday, July 17, 2012 4:50 PM
Subject: Re: EXTERNAL: Re: [vhdl-200x] Directional records proposal



I would agree that iterating through elements of records is required and although I can't think of any obvious examples, I'm sure I've had code in the past that would have benefited from it.

Maybe we need something like a 'foreach rec_type loop' structure to cycle through the record's elements.

On 17/07/2012 16:45, Daniel Kho wrote:


Can a for-loop iterate through the elements of a record? If so, are there any restrictions? This ability would be really nice for converting records of slv elements to one long slv, (and back), etc. But other than that fairly narrow application, I can’t think of any huge benefits of it. Anybody have some other useful applications?


For I in sub_record_type’range loop

  My_vector(j to j + my_record.i’length) := my_record.i;

  J := j + my_record.i’length + 1;

End loop;

I was thinking of using something like this in a resolution function to selectively iterate across a record:

/* same like before. */
type t_cpu_bus is record
end record t_cpu_bus;

/* vector of records that needs to be resolved. */
type t_cpuBusVector is array(natural range <>) of t_cpu_bus;

/* the resolution function - just an idea, more work needed here. */
function resolveRecords(signal someRecordArray: t_cpuBusVector) return t_cpu_bus is
    variable resolvedRecord: t_cpu_bus := (adr | dat => (others=>'0'), we | en => '1', others=>'-'); -- possible use of don't-cares for inputs here?
    /* Here we resolve between 2 records that drive the same signals. But, we need a more complete solution that iterates the resolution of N records.
    /* Loop across elements of record.
        someRecordArray(0) = the record.
        someRecordArray(0).i = one of the record's elements (assume an array type, can be array of std_logic, std_ulogic, bit. unsigned/signed, std_ulogic_vector, bit_vector).
        (someRecordArray(0).i)(j) = one of the record's subelements (assume the subelement is std_ulogic).
    /* Here we are assuming the lengths and datatypes for both records are identical. We can implement extra checks / assertions here.
        I use "someRecordArray(0)" though it may as well be "someRecordArray(1)".
        Note: Accessing i from (someRecordArray(0).i) in the for-declaration may be illegal as of current version of the standard.
    for i in (someRecordArray(0).i)'range loop
        /* Compare the sub-elements of each record type. Here, the sub-elements are concatenated, then compared. */
        case? (someRecordArray(0).i)(j) & (someRecordArray(1).i)(j) is
            when "--" => (resolvedRecord.i)(j) <= '-';
            when "UX" | "XU" => (resolvedRecord.i)(j) <= 'X';
            when "U-" => (resolvedRecord.i)(j) <= (someRecordArray(1).i)(j);
            when "-U" => (resolvedRecord.i)(j) <= (someRecordArray(0).i)(j);
            when "X-" | "-X" => (resolvedRecord.i)(j) <= 'X';
            when "W-" | "-W" => (resolvedRecord.i)(j) <= 'W';
            when "ZZ" => (resolvedRecord.i)(j) <= 'Z';
            when "Z-" => (resolvedRecord.i)(j) <= (someRecordArray(1).i)(j);
            when "-Z" => (resolvedRecord.i)(j) <= (someRecordArray(0).i)(j);
            when "10" | "01" => (resolvedRecord.i)(j) <= 'X';
            when "HH" => (resolvedRecord.i)(j) <= 'H';
            when "11" | "1H" | "H1" => (resolvedRecord.i)(j) <= '1';
            when "00" | "0L" | "L0" => (resolvedRecord.i)(j) <= '0';
            when others => (resolvedRecord.i)(j) <= 'X';
        end case?;
        j := j + someRecordArray(0).i'length + 1;
    return resolvedRecord;
end function resolveRecords;

signal cpu_bus: resolveRecords t_cpu_bus;


This is an example that tries to resolve between 2 records I/Os. More work needed here to have a more generic function that resolves N number of records.
Also, this example tries to resolve _every_ element of the record. We could implement more conditionals within the resolution function to be more selective in resolving only those elements we need.

I have used some constructs that are not supported by the current version of the standard, such as accessing record subelements [using someRecordArray(0).i)(j)], which may need more rethinking.

Another question raised before by Ryan: how do we get the compiler to distinguish between a custom mode and a resolution function?
<quote>Regarding resolution functions, it doesn't make sense to have a user-defined mode for a type with a resolution function. I suggest that such a model be illegal.</quote>

Previously we had this:
bus_rio : m_master t_cpu_bus;
which is a port definition with a custom mode.

And now, to resolve between various records, we have this:
signal cpu_bus: resolveRecords t_cpu_bus;

As suggested before by Ryan, it's probably good to make illegal trying to associate a port or signal to both a resolution function and a custom mode. We should only be able to either associate a resolution function, or a custom mode to a port or signal, not both at the same time. Then it becomes clear and unambiguous to the compiler as to whether a mode association is required or a resolution function is required.







        Brent Hayhoe.


Aftonroy Limited Telephone: +44 (0)20-8449-1852

135 Lancaster Road,

New Barnet, Mobile: +44 (0)79-6647-2574

Herts., EN4 8AJ, U.K. Email:


Registered Number: 1744190 England.

Registered Office:


4th Floor, Imperial House,

15 Kingsway,

London, WC2B 6UN, U.K.




Received on Thu Jul 19 11:06:17 2012

This archive was generated by hypermail 2.1.8 : Thu Jul 19 2012 - 11:07:25 PDT