Initializing an array of records in VHDL - arrays

I have an record defined as follows
type ifx_t is
record
data : std_logic_vector(127 downto 0);
address : std_logic_vector (19 downto 0);
WrReq : std_logic;--
RdReq : std_logic; --
end record;
type Array_ifx_t is array (0 to 2) of ifx_t;
And I have to initialize an instance of this array of records and I have tried the following way and it doesn't work
signal pair_in : Array_ifx_t:= (others =>((others =>'0'),(others=>'0'),'0','0'));
Kindly help.

As said in the comment, ModelSim work when compiling the code from question with ModelSim. However, other tools may be more strict about using a typed value for elements in Array_ifx_t.
For a typed assign and use of named record elements, which I think gives getter overview and avoid mistakes by position references, you can make the initialization with:
constant IFX_T_0S : ifx_t := (data => (others =>'0'),
address => (others=>'0'),
WrReq => '0',
RdReq => '0');
signal pair_in : Array_ifx_t:= (others => IFX_T_0S);

My initial reaction to seeing the aggregate in your default value for pair_in was that there were too many 'others', so I independently wrote one using the record type declaration itself:
library ieee;
use ieee.std_logic_1164.all;
package some_record is
type ifx_t is
record
data : std_logic_vector(127 downto 0);
address : std_logic_vector (19 downto 0);
WrReq : std_logic;--
RdReq : std_logic; --
end record;
type Array_ifx_t is array (0 to 2) of ifx_t;
-- positional association in an aggregate used for initialization:
signal pair_in: ifx_t := ((others => '0'), (others => '0'),'0','0');
end package;
And this analyzed successfully. An aggregate has two types of association, positional or named. The above default value expression is positional. With a named association:
signal pair_in: ifx_t := -- named association of record elements:
(
data => (others => '0'),
address => (others =>'0'),
WrReq => '0',
RdReq => '0'
);
You'll notice this bears an uncanny resemblance to the value expression found in Morten's accepted answer's constant declaration, and actually tells the story of compatibility for an aggregate expression.
An aggregate compatible with a record type contains a value expression that is compatible with each element of the record type. This is done for the array elements data and address by providing aggregates for their default values, while WrReq and RdReq are provided with their default values directly.
The extra others statement found in the original attempt would have been appropriate had pair_in been a composite type comprised of an array comprised of ifx_t record type elements.
The LRM (e.g. IEEE Std 1076-1993) has a section on Expressions, a subsection on Aggregates with a further subsection on Record aggregates.
There's also a section on Types, a subsection on Composite types, with a further subsection on Record types.

Related

VHDL : How to use a 2d-array in generic port as constant?

I'm using QuartusII (version 13.0 or 17.0) and I'm trying to use a 2d-array with a specific type in my entity's generic port, so I can instantiate a MEMORY bloc with one of that 2d-array columns.
In codes, it would look like this :
I have 2 packages, the 1st one is to handle the specific type (fixed type) in which I have a function that converts INTEGER to a configurable size FIXED_type :
library ieee;
use ieee.std_logic_1164.all;
-- PACKAGE DECLARATION
package fixed_pkg is
-- type fixed
type fixed is array (integer range <>) of std_logic;
-- creating a subtype so "fixed" type is easier to write
constant INT : positive := 5;
constant DEC : positive := 5;
subtype t_fixed is fixed(INT-1 downto -DEC);
-- function to convert INT to FIXED
function to_fixed (
val : integer;
l_size : natural;
r_size : natural
) return fixed;
end package fixed_pkg;
-- PACKAGE BODY
package body fixed_pkg is
-- function INT to FIXED
function to_fixed (
val : integer;
l_size : natural;
r_size : natural
) return fixed is
variable result : fixed (l_size-1 downto -r_size);
variable bit_val : std_logic := '0';
variable i_left : integer := val;
begin
result(-1 downto result'right) := (others => '0');
if (i_left < 0) then
bit_val := '1';
i_left := -(i_left)+1;
end if;
for i in 0 to result'left loop
if (i_left mod 2) = 0 then
result(i) := bit_val;
else
result(i) := not bit_val;
end if;
i_left := i_left / 2;
end loop;
return result;
end to_fixed;
end package body fixed_pkg;
The other package is to handle the MEMORY bloc. It contains types, one example of a 2d-array and a function to initialize a MEMORY from a 2d-array :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.fixed_pkg.all;
-- PACKAGE DECLARATION
package some_pkg is
-- rom type
type t_ROM is array (natural range <>) of t_fixed;
-- 2d-array type
type t_2darray is array (natural range <>, natural range <>) of t_fixed;
-- Example of 2d-array
constant ex_2darray : t_2darray (0 to 2, 0 to 2)
:= ((to_fixed(0, INT, DEC), to_fixed(1, INT, DEC), to_fixed(2, INT, DEC)),
(to_fixed(3, INT, DEC), to_fixed(4, INT, DEC), to_fixed(5, INT, DEC)),
(to_fixed(6, INT, DEC), to_fixed(7, INT, DEC), to_fixed(8, INT, DEC))
);
-- function to initialize a ROM bloc
-- <input> init_2darray : 2d array that contains values
-- <input> column_index : selected column in init_2darray that will be copied
-- <input> ROM_size : Size of the return ROM values
-- <output> values from the column_index-th of init_2darray
function init_ROM (
init_2darray : t_2darray;
column_index : natural;
ROM_size : positive
) return t_ROM;
end package some_pkg;
-- PACKAGE BODY
package body some_pkg is
function init_ROM (
init_2darray : t_2darray;
column_index : natural;
ROM_size : positive) return t_ROM is
-- rom values that will be returned
variable ROM_val : t_ROM(0 to ROM_size-1) := (others => to_fixed(0, INT, DEC));
begin
-- filling ROM_val with values from the column_index-th in init_2darray
for addr in 0 to ROM_size-1 loop
ROM_val(addr) := init_2darray(addr, column_index);
end loop;
return ROM_val;
end init_ROM;
end package body some_pkg;
ANNND finally, here is an exemple of instanciation of a bloc MEMORY(ROM) :
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
library work;
use work.some_pkg.all;
use work.fixed_pkg.all;
entity ROM is
generic(
ROM_size : positive := 3;
init_2darray : t_2darray := ex_2darray;
column_index : natural := 0
);
port(
clk : in std_logic;
rdAdd : in natural range 0 to ROM_size-1;
out_data : out t_fixed
);
end ROM;
architecture arch of ROM is
-- ROM instantiation/initialization
constant ROMbloc : t_ROM(0 to ROM_size-1) := init_ROM(init_2darray, column_index, ROM_size);
begin
-- READ PROCESS
process(clk)
begin
if rising_edge(clk) then
out_data <= ROMbloc(rdAdd);
end if;
end process;
end arch;
MY PROBLEM :
In that example of codes I gave, when I try to compile, Quartus throws an "Internal Error". BUT, when I'm using only INTEGER type for the values, I have no problem ...
So I don't really understand what is wrong with my codes... here is the quartus report :
screenshot Quartus Error (Quartus 17.0) when "start compilation"
NB : I'm not using the existing standard fixed package, it's my constraint
Does anyone know how can I handle this problem ?
Thanks for your help !
Apparently, using 2d-array as parameter in the entity generic port works as long as the value type used in the 2d-array is standard.
So the error from quartus appeared when I'm using my function that converts INTEGER to FIXED type in my 2d-array. I found a way to overcome it and I'm not sure it is appropriate but I succeed to make my design compile without error.
In my package, I just keep my values in my 2d-array as INTEGER type like:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.fixed_pkg.all;
-- PACKAGE DECLARATION
package some_pkg is
-- rom type
type t_ROM is array (natural range <>) of t_fixed;
-- 2d-array type
type t_2darray is array (natural range <>, natural range <>) of INTEGER; -- still integer
-- Example of 2d-array
constant ex_2darray : t_2darray (0 to 2, 0 to 2)
:= ((0, 1, 2),
(3, 4, 5),
(6, 7, 8)
);
-- function to initialize a ROM bloc
-- <input> init_2darray : 2d array that contains values
-- <input> column_index : selected column in init_2darray that will be copied
-- <input> ROM_size : Size of the return ROM values
-- <output> values from the column_index-th of init_2darray
function init_ROM (
init_2darray : t_2darray;
column_index : natural;
ROM_size : positive
) return t_ROM;
end package some_pkg;
Then when I initialize my ROM, I do the conversion to FIXED type through my initialization function:
-- PACKAGE BODY
package body some_pkg is
function init_ROM (
init_2darray : t_2darray;
column_index : natural;
ROM_size : positive) return t_ROM is
-- rom values that will be returned
variable ROM_val : t_ROM(0 to ROM_size-1) := (others => to_fixed(0, INT, DEC));
begin
-- filling ROM_val with *converted* values from the column_index-th in init_2darray
for addr in 0 to ROM_size-1 loop
ROM_val(addr) := to_fixed(init_2darray(addr, column_index), INT, DEC); -- I'M DOING THE CONVERSION HERE
end loop;
return ROM_val;
end init_ROM;
end package body some_pkg;
Finally, my goal was to be able to instantiate different ROM components from the 2d-array. In a higher level entity, it would look like:
-- [...]
gen_ROM : for i in 0 to 2 generate
memory : ROM
generic map (
ROM_size : positive := 3;
init_2darray : t_2darray := ex_2darray;
column_index : natural := i
)
port map (
clk => clk,
rdAdd => rdAdd_array(i) -- where rdAdd_array is declared before hand
out_data => out_data_array(i) -- where out_data_array is declared before hand
);
end generate gen_ROM;
-- [...]
where 3 ROM components would be initialized with the columns from the 2d-array.
I hope it will help, just in case someone would face this kind of problem (even if it is specific, I agree).

Multiple processes driving an array of records

The following code showcases an array of records. The particularity is that for each element of the array, the field AR is driven by the process process_AR while the field R is driven by the process process_R.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity test_entity is
end entity;
architecture RTL of test_entity is
-- Try with std_ulogic_vector or std_logic_vector
subtype slv is std_logic_vector;
subtype stdl is slv'element;
type AR_record_t is record
valid : stdl;
addr : slv(15 downto 0);
end record;
type R_record_t is record
ready : stdl;
data : slv(31 downto 0);
end record;
type axil_record_t is record
AR : AR_record_t;
R : R_record_t;
end record;
type array_of_axil_record_t is array(natural range <>) of axil_record_t;
signal axil_read_channel : array_of_axil_record_t(0 to 1);
begin
-- Process only deal with the AR channel
process_AR : process
begin
wait for 20 ps;
axil_read_channel(0).AR <= (valid => '1', addr => X"CAFE");
axil_read_channel(1).AR <= (valid => '0', addr => X"DEAD");
end process;
-- Process only deal with the R channel
process_R : process
begin
wait for 20 ps;
axil_read_channel(0).R <= (ready => '0', data => X"12345678");
axil_read_channel(1).R <= (ready => '1', data => X"89ABCDEF");
end process;
end architecture;
This code works as (I) expected.
However, change the process_AR by the following (using a for loop now):
-- Process only deal with the AR channel
process_AR : process
begin
wait for 20 ps;
for i in axil_read_channel'range loop
axil_read_channel(i).AR <= (valid => '1', addr => X"CAFE");
end loop;
end process;
When using non-resolved types (std_ulogic and std_ulogic_vector), this new code fails:
(vsim-3344) Signal "/test_entity/axil_read_channel(0).R.ready" has multiple drivers but is not a resolved signal.
I guess the for loop does not work because the it is sort of a 'dynamical' assignment and therefore axil_read_channel is considered instead of axil_read_channel(i) ?
On the other hand, the first version of the code (with hard coded '0' and '1') uses sort of 'static' assignment and therefore considers the two elements axil_read_channel(0) and axil_read_channel(1) as two signals and not element of an array ?
When using resolved types (std_logic and std_logic_vector):
What is the reason behind the difference of behavior between the first code and second code ?
Is there a work around not involving for-generate (not applicable to my current design) for synthesis ?
When you use a loop in a process to drive a signal of a composite type (array or record), the elaboration cannot determine which specific objects require a driver at elaboration time, hence it has to assume all objects within the composite type require a driver. This then creates a driver for the entire array/record, rather than each element that would have occured without the loop.
This is what is causing your error when you use resolved/unresolved types. The errors occurs with the unresolved types std_ulogic(_vector) because they are not allowed multiple drivers. The resolved types std_logic(_vector) are allowed multiple drivers and all of the elements undriven by you will have 'U' driven on them.
Addressing your question, is there a work around. Probably. Do your tools support VHDL-2008 aggregates with unconstrained elements? If yes, the following may work (have not tried it):
-- continuing from your above declarations:
type array_of_AR_record_t is array(natural range <>) of AR_record_t;
type array_of_R_record_t is array(natural range <>) of R_record_t;
type axil_record_t is record
AR : array_of_AR_record_t;
R : array_of_AR_record_t;
end record;
signal axil_read_channel : axil_record_t (AR(0 to 1), R(0 to 1)) ;
. . .
-- Process only deal with the AR channel
process_AR : process
begin
wait for 20 ps;
for i in axil_read_channel.AR'range loop
axil_read_channel.AR(i) <= (valid => '1', addr => X"CAFE");
end loop;
end process;
We are looking at language changes in the next revision that could help simplify the declarations. See: https://gitlab.com/IEEE-P1076/VHDL-Issues/-/issues/81

Creating a 2D-Array Field in an Ada Tagged Type

I'm trying to create a Java/C class equivalent in Ada. From what I've researched -- the equivalent would be a Tagged Record. I'm wanting to create a field that is a 2D Array, however with the code below -- it gives me the following errors.
Code:
package Foo is
type Bar is tagged
record
field1 : Integer;
field2 : Integer;
type field3 is array (1 .. 10, 1 .. 5) of Integer;
end record;
end Foo;
Error:
foo.ads:6:25: missing "end record;" for "record" at line 8
foo.ads:7:17: no "record" for this "end record"
This tells me that "Anonymous arrays are not allowed as components".
package Foo is
type Bar is tagged
record
field1 : Integer;
field2 : Integer;
field3 : array (1 .. 10, 1 .. 5) of Integer;
end record;
end Foo;
The reason your second version fails is that
field3 : array (1 .. 10, 1 .. 5) of Integer;
declares a new, unnamed (anonymous), type (array (1 .. 10, 1 .. 5) of Integer), and you’re not allowed to nest type declarations.
Depending on your application, you might try
type Twod_Array is array (Integer range <>, Integer range <>) of Integer;
type Bar is tagged
record
field1 : Integer;
field2 : Integer;
field3 : Twod_Array (1 .. 10, 1 .. 5);
end record;
or
type Twod_Array is array (Positive range <>, Positive range <>) of Integer;
type Bar (First, Second : Natural) is tagged
record
field1 : Integer;
field2 : Integer;
field3 : Twod_Array (1 .. First, 1 .. Second);
end record;
[Hmm. I said First, Second : Natural to allow for zero-length arrays. But I’m not sure what the point of A_Bar : Bar (0, 10); would be!]
You attempt to declare one named type inside the declaration of another named type. You can't do that.
Also, Ada does not allow record fields of anonymous types, so you have to ensure that you have declared all the types you need for the fields of your record, before the declaration of the record itself.
Are you sure you need values in the range -32_768 .. 32_767 (that's all Ada promises about the type Integer)? Normally one would declare a type matching the requirements of the problem. (Of course, if the problem is to match the C type int closely, then one should use Interfaces.C.int.)

Can we restrict the index order of an array parameter for a procedure?

Lets say we have a behavioural VHDL procedure for a testbench:
procedure jtag_load_data(data : in std_ulogic_vector) is
begin
jtag_clock(1, '1', '0');
jtag_clock(2, '0', '0');
for i in data'length-1 downto 1 loop
jtag_clock(1, '0', data(i));
end loop;
jtag_clock(2, '1', data(0));
jtag_clock(1, '0', data(0));
end procedure;
This procedure can either be called with a constant parameter like so
jtag_load_data("100")
or the parameter can be computed from others like this
jtag_load_data(tmasrc & tdosrc & tm)
Since VHDL arrays don't define the index order, I think the order the bits of data are processed within the for loop depends on the index of the data parameter when the procedure is called.
In case that wasn't clear, say a is of type std_logic_vector(3 downto 0) and b is of type std_logic_vector(0 to 3) and we do the following:
a <= "100";
b <= "100";
jtag_load_data(a);
jtag_load_data(b);
The bits processed for a will be 1, 0, 0 while for b they will be 0, 0, 1.
Back to my original two calling examples, this is a problem for the case where the parameter is a concatenation of std_logic_vectors: The expression tmasrc & tdosrc & tm (all three operands are of type std_logic_vector(n downto 0)) seems to evaluate to a std_logic_vector(0 to m), which reverses the order the bits are processed with respect to the case where I call the procedure with just one of the parameters (or a constant, which seems to default to the downto index ordering).
To fix this ambiguity, we can introduce a variable with known index order ordered_data like so:
procedure jtag_load_data(data : in std_ulogic_vector) is
variable ordered_data : std_ulogic_vector(data'length-1 downto 0);
begin
ordered_data := data;
jtag_clock(1, '1', '0');
jtag_clock(2, '0', '0');
for i in ordered_data'length-1 downto 1 loop
jtag_clock(1, '0', ordered_data(i));
end loop;
jtag_clock(2, '1', ordered_data(0));
jtag_clock(1, '0', ordered_data(0));
end procedure;
But I am wondering if there is a more elegant VHDL syntax to say either
"please interpret all data values passed into the procedure as having decreasing indexes" or
"please produce a std_logic_vector of decreasing indexes when concatenating them as in tmasrc & tdosrc & tm".
If you don't specify a range on a std_ulogic_vector (or std_logic_vector) input to a procedure (or function) then inside the procedure the left hand bit is always 0 and the bit numbers increase left to right. This is because a std_ulogic_vector is declared thus:
type std_ulogic_vector is array (natural range <>) of std_ulogic;
and since the index type is a natural whose left hand value is 0, the left hand element is always numbered 0 with an unconstrained parameter such as this.It is exactly the same for a std_logic_vector, which is declared the same way.
The numbering is not passed in from outside the procedure. Whatever is on the left outside the procedure (the actual) is numbered 0 inside the procedure (the formal).
So, in your example:
In case that wasn't clear, say a is of type std_logic_vector(3 downto
0) and b is of type std_logic_vector(0 to 3) and we do the following:
a <= "100"; b <= "100"; jtag_load_data(a); jtag_load_data(b);
a and b will be processed in exactly the same way; there is no difference; the fact that a is of type std_logic_vector(3 downto 0) and b is of type std_logic_vector(0 to 3) is irrelevant.
So, to answer your specific questions: it is up to you to ensure that the inputs are passed into the procedure in the correct order. If that is no good, then you need to pass in some other parameter to control the direction.

Adressing a specific bits in an array of std_logic vector in VHDL

Im new to VHDL.
my problem is that i cant seem to find the correct syntax for writing or reading from an array of std_logic_vector. i init the array as such :
TYPE eleven_samples_in IS ARRAY ( 0 TO 10 ) OF STD_LOGIC_VECTOR( 87 DOWNTO 0 );
and i try addressing it as such :
odd: for i in 1 to 6 generate
node: compare_level
port map(
input => eleven_samples_in(i*2 - 1)(79 DOWNTO 0),
output => eleven_samples_out(i*2 - 1)(79 DOWNTO 0 )
);
end generate odd;
Or :
port map(
input => eleven_samples_in(i*2 - 1,79 DOWNTO 0),
output => eleven_samples_out(i*2 - 1,79 DOWNTO 0 )
);
end generate odd;
But i get an Errors such as :
Error (10409): VHDL Type Conversion error at Median_Filter.vhd(45): converted type of object near text or symbol "eleven_samples_in" must match std_logic_vector type of target object
I searched the web and found nothing that works.
thank you very much for the help .
you create a type eleven_samples_in, and use that directly. This is incorrect.
Instead:
type eleven_samples_in_type is array (0 to 11) of std_logic_vector(89 downto 0);
signal eleven_samples_in : eleven_samples_in_type;
...
Without knowing anything about your compare_levels component, thats as much help as I can be
To answer about the right syntax to access specific bits from an array of std_logic_vector, as I was wondering myself, it happens to be the first you suggested:
s_array(array_index)(vector_bit_index) -- for a single bit
or
s_array(array_index)(last_bit_index downto first_bit_index) -- for a range

Resources