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