RE: EXTERNAL: Re: [vhdl-200x] Directional records proposal

From: Huffman, Nathanael D (GE Healthcare) <Nathanael.Huffman@ge.com>
Date: Tue Jul 17 2012 - 15:02:27 PDT

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.

Nathanael

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

Daniel,

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:
Andy,
<quote>

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;
</quote

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

<code>
/* 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?
begin
    /* 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. E.gs.: 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;

</code>

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.

-daniel

--
Regards,
        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: Brent.Hayhoe@Aftonroy.com<mailto:Brent.Hayhoe@Aftonroy.com>
Registered Number: 1744190 England.
Registered Office:
4th Floor, Imperial House,
15 Kingsway,
London, WC2B 6UN, U.K.
Received on Tue Jul 17 15:03:52 2012

This archive was generated by hypermail 2.1.8 : Tue Jul 17 2012 - 15:03:57 PDT