Initializing arrays in VHDL: How exactly does it work? - arrays

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).

Related

Unsigned addition in VHDL resulting in incorrect length unsigned result

update
#user1155120's comment below is correct:
This is telling you the error is somewhere in the realm of -- other assignments here
I had multiplication operations which I mistakenly believed functioned in the same manner as addition. My mistake.
I am working on a rudimentary ALU using VHDL.
Here is the code which is throwing an error:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_misc.all;
entity alu is
port (
A, B : in unsigned(31 downto 0);
sel : in unsigned(2 downto 0);
O : out unsigned(63 downto 0));
end entity alu;
architecture Behavioral of alu is
begin
O <= resize(A, 64) + resize(B, 64) when sel = "000"
-- other assignments here
end Behavioral;
My understanding of Unsigned addition in VHDL is that the length of the sum will be equal to the longest length of the operands. However, my code gives the following error:
ERROR: Array sizes do not match, left array has 64 elements, right array has 128 elements
Strange. However, if I change the resize values to be less than 64 bits, then the behavior follows my expectation (width=max width of operands). Like this:
O <= resize(A, 33) + resize(B, 33) when sel = "000"
I get the following error:
ERROR: Array sizes do not match, left array has 64 elements, right array has 33 elements
I end up being very confused. Why is the width of the output changing when I resize only to a certain value?
I am using the student license for Vivado 2020.
You probably have
O <= resize(A, 64) * resize(B, 64) when sel = whatever
Somewhere in your code on a lower line and you're messing up the line numbers when you read the error. The moment you change the addition to be wrong, that's the first line analysis fails on and you get the error you see now.

VHDL Generate Array Of STD_LOGIC_VECTORS with Reducing Length

I am trying to create an array of std_logic_vectors with reducing lengths. I have tried making an array with a generic std_logic_vector and then using a generate statement to make the vectors.
architecture behavioral of dadda_mul_32bit is
type and_planes is array (0 to 31) of std_logic_vector;
begin
generate_and_plane:
for i in 0 to 31 generate
and_planes(i) <= and_vector(a, b(i), i);
end generate generate_and_plane;
end behavioral;
along with a function that returns a generic std_logic_vector:
function and_vector(vec: std_logic_vector; x: std_logic; length: natural) return std_logic_vector is
variable result: std_logic_vector(length - 1 downto 0);
begin
for i in 0 to length - 1 loop
result(i) := vec(i) and x;
end loop;
return result;
end function;
Am I using the generate statement incorrectly?
and_planes is a type not a signal, so you can't assign to it!
More over you are creating a partially constrained type, which needs to be constrained in a object (e.g. signal) declaration.
VHDL doesn't support ragged arrays. (Arrays wherein each element is of different size). If you need this for simulation, you can use access types and emulate ragged arrays like in C. If you need it for synthesis, then you can emulate a ragged array with a one-dimensional array and some functions to compute the bounds of a nested vector.
See this answer of me:
VHDL Multidimensional arrays with different internal size
vhdl port declaration with different sizes
Btw. VHDL-2008 adds an overload: "and"(std_logic, std_logic_vector), so no function is needed to calculate the anding of a single bit with each bit in a vector.
-- slice 'a' and gate it by 'b(i)'
and_planes(i) <= a(i downto 0) and b(i);

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.

2D Unconstrained Nx1 Array

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.

Resources