2D Unconstrained Nx1 Array - arrays

I'm trying to create a flexible array of constants. I want to use a 2D array which may sometimes be for example a 2x1, 2x2, 3x2 array etc. For example:
type int_2d_array is array (integer range<>, integer range<>) of integer;
constant M : positive := 2;
constant nMax : positive := 1;
constant n : int_2d_array(M - 1 downto 0, nMax - 1 downto 0) := ( (1) , (2) ); -- wrong
error: type int_2d_array does not match with the integer literal
If I do this, it doesn't complain:
type int_2d_array is array (integer range<>, integer range<>) of integer;
constant M : positive := 2;
constant nMax : positive := 2;
constant n : int_2d_array(M - 1 downto 0, nMax - 1 downto 0) := ( ( 0,1 ) , ( 2,2 )); -- accepted
Is the first example even possible using a 2D array?

The LRM (section 9.3.3 Aggregates) states:
Aggregates containing a single element association
shall always be specified using named association in order to distinguish them from parenthesized expressions.
So, this is OK:
constant n : int_1d_array(0 downto 0) := ( 0 => 1 );
and this is not:
constant n : int_1d_array(0 downto 0) := ( 1 );
http://www.edaplayground.com/x/6a4

I managed to compile the first example in the following ugly way:
type int_2d_array is array (integer range<>, integer range<>) of integer;
constant M : positive := 2;
constant nMax : positive := 1;
constant n : int_2d_array(M - 1 downto 0, nMax - 1 downto 0) := ( (others => 1) , (others => 2) );
Strange behavior, indeed.

Related

Initializing arrays in VHDL: How exactly does it work?

Consider the following VHDL code:
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1', others => '0');
Here, the indices 7 and 6 are important: they indicate which elements should be 1, and from that, the compiler can derive which ones should be 0.
Question 1
If I understand correctly, this can also be written as
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1') & (5 downto 0 => '0');
Now I am wondering how exactly this works, and whether the indices still matter or only the difference between them. The way I understand it, the expression (x downto y => z) creates an array with indices x downto y, whose elements are all equal to z (and have the same type). But do these indices matter when arrays are concatenated? I.e., could I also write any of the following:
constant c : std_logic_vector(7 downto 0) := (1 downto 0 => '1') & (5 downto 0 => '0');
constant c : std_logic_vector(7 downto 0) := (99 downto 98 => '1') & (4 downto -1 => '0');
Of course one could say that those statements, esp. the last one, aren't really clear, but my question is: Would they have the same result? Or would they cause some kind or error?
The reason I am wondering about this is that you could also write
constant c : std_logic_vector(7 downto 0) := "11" & "000000";
and the literal "11" doesn't have any range specified, so I'm not sure what exactly the type of this literal would be, but certainly not std_logic_vector(7 downto 6).
Question 2
Finally, I am wondering what is the difference between
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1') & (5 downto 0 => '0');
and
constant c : std_logic_vector(7 downto 0) := (7 downto 6 => '1', 5 downto 0 => '0');
By this I mean: Is there any reason you would want/need to write the former (which seems more error-prone because it will give unexpected results if you e.g. swap the 2 aggregates) instead of the latter? Or is it just a matter of taste?
Lets start with literals. When you specify a literal, the default range is (type_index'low to type_index'low + len-1). The easiest way to see this is when specifying a constant, where the range is not required in the subtype:
constant SOME_CONSTANT : std_logic_vector := x"00";
Here, if you check the range of SOME_CONSTANT, you'll see its (0 to 7). This is because std_logic_vector is declared as:
type std_ulogic_vector is array(natural range <>) of std_logic;
The 'low value of natural is 0, which is the start point.
Lets say you went a bit crazy, and this:
type my_crazy_array_t is array(std_logic range <>) of integer;
and you declared a constant:
constant CRAZY : my_crazy_array_t := (0, 22);
The results are:
CRAZY('U') = 0
CRAZY('X') = 22
CRAZY'left = 'U'
CRAZY'right = 'X'
CRAZY'low = 'U'
CRAZY'high = 'X'
Because 'U' is the low value of std_logic, followed by 'X'.
On the other questions, it all works because VHDL is always context driven, and for arrays as long as the lengths match, the resulting arrays can always be mapped from 'left to 'right. In your examples the length is correct, and the subtype is know from the declaration, so mapping can occur as you specified.
NOTE: (4 downto -1 => '0'); is illegal, because -1 is not a valid index value for a std_logic_vector, so you would get an error (probably from the & function because it cannot work out what type you meant, because it cannot be std_logic_vector).
The difference is that the first one is a concatenation of a 2 bit and 6 bit bit string, and the 2nd is a complete 8 bit bit string. Which you use will probably be a matter of style. But usually, for this, I would use literals eg: constant c : std_logic_vector(7 downto 0) := x"C0"; what you use and when may depend on what is clearest to the user(s).

Array of array of records

I need to create a constant array of a constant array of records where I can reference each element of the outer array by a number.
I've tried:
A : constant array (0 .. 3) of B := (B1, B2, B3, B4)
where B is an array of records and B1,B2,B3,B4 are constant arrays of type B.
But when I do this I get the error:
"Unconstrained element type in array declaration"
type C is record
a : Integer := 0;
b : Integer := 0;
c : Integer := 0;
d : Integer := 0;
end record;
type B is array (Natural range <>) of C;
B1 : constant B := (0, 0, 0, 0);
B2 : constant B := (2, 0, 2, 0);
B3 : constant B := (0, 1, 0, 1);
B4 : constant B := (2, 1, 2, 1);
A : constant array (0 .. 3) of B := (B1, B2, B3, B4);
I was hoping to use A to be able to reference B1,B2,B3,B4 numerically like so:
A (1) returns B1
A (2) returns B2
and so on...
(I apologize if the terms I use are wrong. I'm kinda new to Ada and have been learning by trial and error...)
Your problem is that B is an unconstrained array:
type B is array (Natural range <>) of C;
This is fine for B1 : constant B := (0, 0, 0, 0);, as the constant definition creates a new anonymous type, with the range taken from the Right-Hand-Side.
It is, however, not fine for A. The compiler needs to know the size of the array elements, but cannot when the element (B in this case) is unconstrained. In addition, the constraints ('First, 'Last, etc) must be the same for all of the elements.
You can change your definition of B to be constrained:
type B is array (Natural range 1..4) of C;
This will force all your B1, B2, etc to always have four elements, which is what you already have in your example.
Also, if you want A(1) to return B1, you should change the range of A to start at 1:
A : constant array (1 .. 4) of B := (B1, B2, B3, B4);
What is obvious to you is not obvious to the compiler, that is all your B's have four elements.
For accessing element A(3)(2) it (or the Ada language) wants to be able to make very simple arithmetic (2 + 3 * 4) * (size of an integer). An array of B (which is unconstrained) would make this computation too complicated. The produced machine code would need to add the sizes of A(0), A(1), A(2) just to get to A(3)(0).
Of course you can imagine the time it would take for much larger array lengths, just for accessing element A(1234)(5678) for instance.
This is why the designers of Ada wisely required to have always arrays of constrained types. For your problem, you can solve it by defining subtype BL4 is B (0 .. 3); and use BL4 instead of B for B1, B2, B3, B4 and A.

VHDL assignment to an array type

Consider a type
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
Why do I get a compiler error when I try to create a constant value of this type, for example. Note that I have only tried using Altera's Quartus II.
constant cFoo : foo := ( x"11" );
Error: VHDL Type mismatch error at [filename.vhd](line number): cFoo type does not match string literal.
However everything is ok if my type is
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
with an example assignment to a constant of:
constant cFoo : foo := ( x"00", x"11" );
Moreover consider that I try to assign index 0 with another constant. For example.
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
constant cBar : std_logic_vector(7 downto 0);
constant cFoo : foo := ( cBar );
To which the error the compiler spits out is now:
VHDL error at [filename.vhd](line number): type of identifier "cBar" does not agree with its usage as "foo" type.
So basically its telling me that the compiler does not realize that the assignment is to the index of 0 but instead an assignment to the the array type.
How can I let the compiler know that the assignment is to only index 0?
IEEE Std 1076 9.3.3 Aggregates, 9.3.3.1 para 4:
Both named and positional associations can be used in the same aggregate, with all positional associations appearing first (in textual order) and all named associations appearing next (in any order, except that it is an error if any associations follow an others association). Aggregates containing a single element association shall always be specified using named association in order to distinguish them from parenthesized expressions.
With an MCVE:
library ieee;
use ieee.std_logic_1164.all;
package ceefoo is
type foo is array (0 downto 0) of std_logic_vector(7 downto 0);
-- constant cFoo : foo := ( x"11" );
constant cfoo: foo := (0 => x"11");
-- or
constant cefoo: foo := (others => x"11");
end package;
You need to use named association with a single element. The first example specifies index 0, the second any elements.
Para 3 of the above quoted subsection:
Each element association associates an expression with elements (possibly none). An element association is said to be named if the elements are specified explicitly by choices; otherwise, it is said to be positional. For a positional association, each element is implicitly specified by position in the textual order of the elements in the corresponding type declaration.
It's helpful to see the BNF:
aggregate ::=
( element_association { , element_association } )
element_association ::=
[ choices => ] expression
choices ::= choice { | choice }
choice ::=
simple_expression
| discrete_range
| element_simple_name
| others

VHDL - array of std_logic_vectors convert into std_logic_vector

INTENTION:
I am reading data from RAM on ZedBoard, the RAM consists of 32 bits long words so I use the following buffer
type mem_word is array (0 to 127) of std_logic_vector(31 downto 0);
signal buffer_word : mem_word;
but then, I would like to address data in a linear fashion, in an intermediary linear buffer
signal buffer_linear : std_logic_vector(4095 downto 0);
buffer_linear <= buffer_word; -- !!! PROBLEM
so I can easily address any bit in the buffer without recalculating the position in specific word (of the buffer_word).
QUESTION:
How do I get from array of std_logic_vectors into 1 long std_logic_vector ? Is there a way to avoid concatenating 128 words in a loop ? (something like above buffer_linear <= buffer_word;)
You need a function to convert from vector-vector to a 1-dimensional vector.
My following example uses the type name T_SLVV_32 to denote that it is a vector of vectors, wherin the inner vector is 32 bit long. (See my linked source file, for a true 2-dimensional STD_LOGIC matrix type called T_SLM). So T_SLVV_32 is equivalen to your mem_word type.
subtype T_SLV_32 is STD_LOGIC_VECTOR(31 downto 0);
type T_SLVV_32 is array(NATURAL range <>) of T_SLV_32;
function to_slv(slvv : T_SLVV_32) return STD_LOGIC_VECTOR is
variable slv : STD_LOGIC_VECTOR((slvv'length * 32) - 1 downto 0);
begin
for i in slvv'range loop
slv((i * 32) + 31 downto (i * 32)) := slvv(i);
end loop;
return slv;
end function;
Usage:
buffer_linear <= to_slv(buffer_word);
This function creates no logic, just wiring.
Note: Accessing all bits of a memory at once, prevents synthesis tools of inferring RAM or ROM memory blocks!
Source: PoC.vectors
See my vector package at GitHub for more examples on transforming vectors and matrices forth and backwards.

$size, $bits, verilog

What is the difference between $size and $bits operator in verilog.?
if I've variables, [9:0]a,[6:0]b,[31:0]c.
c <= [($size(a)+$size(b)-1]-:$bits(b)];
What will be the output at 'c' from the above expression?
$size() gives the number of bits for a single dimension. $bits() gives the number of bits to completely represent the variable.
For example:
reg [9:0] a;
reg [9:0] b [5:0];
initial begin
$display("a Size ", $size(a));
$display("a Bits ", $bits(a));
$display("b Size ", $size(b));
$display("b Bits ", $bits(b)) ;
end
Gives :
a Size 10
a Bits 10
b Size 6 // Depth of memory
b Bits 60 // Width * Depth
In your case you just have 1 dimensional arrays, not memories or structs so $size() and $bits() would be the same thing.
$size shall return the number of elements in the dimension, which is equivalent to $high - $low + 1. It is relative to the dimension, not only bit counts. If the type is 1D packed array or integral type, it is equal to $bits.
$bits system function returns the number of bits required to hold an expression as a bit stream.
$bits ( [expression|type_identifier] )
It returns 0 when called with a dynamically sized type that is currently empty. It is an error to use the $bits system function directly with a dynamically sized type identifier.
I have no idea about your question, c <= [($size(a)+$size(b)-1]-:$bits(b)];. Is it a valid expression in RHS? Are you talking about the array range expression, [n +: m] or [n -: m] ?

Resources