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

From: Peter Flake <flake@elda.demon.co.uk>
Date: Wed Jul 18 2012 - 07:31:12 PDT

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.

 

Peter.

 

From: owner-vhdl-200x@eda.org [mailto:owner-vhdl-200x@eda.org] On Behalf Of
Huffman, Nathanael D (GE Healthcare)
Sent: 17 July 2012 23:02
To: vhdl-200x@eda.org
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.

 

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
 
Registered Number: 1744190 England.
Registered Office:
 
4th Floor, Imperial House,
15 Kingsway,
London, WC2B 6UN, U.K.
 
 
Received on Wed Jul 18 07:31:20 2012

This archive was generated by hypermail 2.1.8 : Wed Jul 18 2012 - 07:31:51 PDT