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

From: Daniel Kho <daniel.kho@gmail.com>
Date: Wed Jul 18 2012 - 13:02:49 PDT

<quote>...Each field can have a different data type...</quote>
Yes, but let's assume everything resolves down to std_ulogic at the finest
element level, so we only need to deal with vectors of std_ulogics, or
matrices of std_ulogics, etc.
For example, (un)signed is a vector of std_ulogic, and for other vector
types, type conversions may be needed, as in the case of bit_vectors or
boolean_vectors for example. For scalar types (integer, real, etc.), we
could use conversion functions to convert to vectors of std_ulogics.

Ryan, would this work for you in the case of resolution functions?
From your example, say we have the signal "obj" driven by two different
processes/blocks. Assume only the "snum" field is being driven by both
processes, and "int" and "float" are inputs to both blocks (so they are not
being driven).

 type misc_vector is array(natural range<>) of misc;

 -- object of this type

 signal obj : resolveObjects misc;

 mode m_mode of misc is (snum => out, others => in);

 ...

 function resolveObjects(signal misc_vct: in misc_vector) return misc is

  -- loop over fields and resolve elements with multiple drivers.

  for field in misc'fields loop

    --resolve only fields that have an "out" mode/direction (only "out"s
will cause the multiple driver problem).

    --Inputs are ignored since they are fanned out.

    if field'mode = out then

        ... -- multiple driver outputs for obj.snum will be resolved.

    end if;

  end loop;

 end function resolveObjects;

 --example instance

 entity master is port(

      clk, rst : in std_logic;

      bus_rio : m_mode misc

   );

 end entity master;

Any problems with doing something like this?

regards, daniel

On 19 July 2012 01:25, <ryan.w.hinton@l-3com.com> wrote:

> 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.****
>
> ** **
>
> Enjoy!****
>
> ** **
>
> - Ryan****
>
> ** **
>
> *From:* owner-vhdl-200x@eda.org [mailto:owner-vhdl-200x@eda.org] *On
> Behalf Of *Peter Flake
> *Sent:* Wednesday, July 18, 2012 8:31 AM
> *To:* vhdl-200x@eda.org
> *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.****
>
> ** **
>
> 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<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 Thu, 19 Jul 2012 04:02:49 +0800

This archive was generated by hypermail 2.1.8 : Wed Jul 18 2012 - 13:03:43 PDT