VHDL Column selection from array - vhdl

type matrixsignal is array (LEVELS downto 0) of std_logic_vector(NBIT-1 downto 0);
signal p_matrix, g_matrix: matrixsignal;
signal col_temp_g, col_temp_p : std_logic_vector(LEVELS downto 0);
...
col_temp_p<=p_matrix(LEVELS downto 0)(j-1);
col_temp_g<=g_matrix(LEVELS downto 0)(j-1);
Hello everyone!
I want to select and copy the entire column (j-1) of the 2 arrays...but the compiler tells me that this way is not the correct one.
How is it possible to do it?
P.S. LEVELS,NBIT,j are initialized parameters...I did not report their initialization.

You should define matrixsignal as a 2-dimensional array instead of a one-dimensional array that nests another 1-dimensional array.
type matrixsignal is array(LEVELS downto 0, NBIT - 1 downto 0) of std_logic;
The PoC-Library offers that type as T_SLM (std_logic_matrix) together lot's of manipulation functions and procedures in package PoC.vectors. E.g. PoC defines a get_col function like this:
function get_col(slm : T_SLM; ColIndex : natural) return std_logic_vector is
variable slv : std_logic_vector(slm'range(1));
begin
for i in slm'range(1) loop
slv(i) := slm(i, ColIndex);
end loop;
return slv;
end function;
Usage:
subtype matrixsignal is T_SLM(LEVELS downto 0, NBIT - 1 downto 0);
signal p_matrix, g_matrix : matrixsignal;
signal col_temp_g, col_temp_p : std_logic_vector(LEVELS downto 0);
...
col_temp_p <= get_col(p_matrix, j - 1);
col_temp_g <= get_col(g_matrix, j - 1);
The package PoC.vectors can be synthesized.
Further functions are provided like:
slicing a complete row
slicing sub matrixes
flattening / serialization
creating matrix from vector / deserialization
overloaded boolean operators
row / column assignment
matrix merging
conversion to/from 1-dimensional array types containing another 1-dimensional array type
...

Related

VHDL logic vector to record assignment

Suppose I have defined a record with fields of std_ulogic_vector to represent a larger std_ulogic_vector. It's straightforward to convert this record to the large vector using a concatenation (without knowledge of the size for each field).
How do I do the reverse, e.g. convert the large std_ulogic_vector back to the record ?
Example :
architecture RTL of record_conversion is
type data_t is record
top : std_ulogic_vector(4 downto 0);
bottom : std_ulogic_vector(2 downto 0);
end record data_t;
signal record_s : data_t;
signal vector_s : std_ulogic_vector(7 downto 0);
begin
-- vector to record works
--vector_s <= record_s.top & record_s.bottom;
-- record to vector does not work
(record_s.top, record_s.bottom) <= vector_s;
-- tedious solution with knowledge of the field size
record_s.top <= vector_s(7 downto 3);
record_s.bottom <= vector_s(2 downto 0);
end architecture;
It is usually a good idea to wrap such conversion in functions, and with a subtype for resulting vector, like:
...
constant LEN : integer := 8; -- Number of bits in data_t
type data_t is record
top : std_ulogic_vector(4 downto 0);
bottom : std_ulogic_vector(2 downto 0);
end record data_t;
subtype vector_t is std_ulogic_vector(LEN - 1 downto 0);
function data_to_vector(data : data_t) return std_ulogic_vector is
variable res_v : vector_t;
begin
res_v := data.top & data.bottom;
return res_v;
end function;
function vector_to_data(vector : vector_t) return data_t is
variable res_v : data_t;
begin
res_v.top := vector(LEN - 1 downto LEN - res_v.top'length);
res_v.bottom := vector(res_v.bottom'length - 1 downto 0);
return res_v;
end function;
signal record_s : data_t;
signal vector_s : vector_t;
begin
record_s <= vector_to_data(vector_s);
vector_s <= data_to_vector(record_s);
...
Maybe another constant should be added to define the split between top and bottom.
There are a couple of other methods besides using subprogram calls to assign elements of one type to elements of another type.
You can use a qualified expression:
record_s <= data_t'(vector_s(7 downto 3), vector_s (2 downto 0));
Where the aggregate comprised of two slices of vector_s with an explicit type matching the record. See IEEE Std 1076-2008 9.3.6 Qualified expressions.
During simulation new values for signals are validated. See 14.7.3.4 Signal update:
b) If S is a composite signal (including a slice of an array), the effective value of S is implicitly converted to the subtype of S. The subtype conversion checks that for each element of S there is a matching element in the effective value and vice versa. An error occurs if this check fails. The result of this subtype conversion is then assigned to the variable representing the current value of S.
Besides having a matching element (subelement,...) subtype conversion changes the index ranges to match the target.
You can specify the slice index ranges with subtype index ranges:
library ieee;
use ieee.std_logic_1164.all;
entity record_conversion is
end entity;
architecture subtypes of record_conversion is
type data_t is record
top : std_ulogic_vector(4 downto 0);
bottom : std_ulogic_vector(2 downto 0);
end record data_t;
signal record_s : data_t;
signal vector_s : std_ulogic_vector(7 downto 0);
subtype t is std_logic_vector (
vector_s'LEFT downto vector_s'LEFT - record_s.top'length + 1
);
subtype b is std_logic_vector (
vector_s'LEFT - record_s.top'length downto 0
);
begin
record_s <= data_t'(vector_s(t'range), vector_s(b'range));
end architecture;
Here the subtypes index range slices of the right hand side expression elements.
You can describe the slices with aliases:
architecture aliases of record_conversion is
type data_t is record
top: std_ulogic_vector(4 downto 0);
bottom: std_ulogic_vector(2 downto 0);
end record data_t;
signal record_s: data_t;
signal vector_s: std_ulogic_vector(7 downto 0);
alias vector_s_top: std_ulogic_vector(record_s.top'range) is
vector_s(7 downto 3);
alias vector_s_bottom: std_ulogic_vector(record_s.bottom'range) is
vector_s (2 downto 0);
begin
record_s <= data_t'(vector_s_top, vector_s_bottom);
end architecture;
Here the two aliases describe fields of vector_s. If you were guaranteed to always assign the record composite object you could actually do away with records and simply use aliases. The closest VHDL comes to unions.
The above examples analyze, elaborate and simulate without error, demonstrating there are no slice boundary issues.
Qualified expressions, subtype declarations and aliases incur no additional simulation overhead while subprogram calls do.

Direction independent slicing

I'm creating a package with some functions I often use and some functions need to take slices of their parameters. I usually use downto direction for all my signals, but sometimes signals change their direction unexpectedly, e.g., appending a zero bit (sig & '0') seems to change the direction to positive.
Is there a way to slice arrays (std_logic_vector, unsigned, signed) independent of their direction? For example how would you implement a function taking the lowest two bits? The only implementation I came up with uses an additional constant with the expected direction:
function take_two(x : std_logic_vector) return std_logic_vector is
constant cx : std_logic_vector(x'length-1 downto 0) := x;
begin
return cx(1 downto 0);
end function;
I've also tried something like x(x'low+1 downto x'low) but Quartus doesn't like this.
The question is actually not on the input, but on the required output. What do you prefer?
If you look at how functions are implemented in for instance std_logic_1164-body.vhdl, your function would similarly be something like (in a complete example):
entity e is end entity;
library ieee;
architecture a of e is
use ieee.std_logic_1164.all;
signal test : std_logic_vector(7 downto 0) := "10010110";
signal output : std_logic_vector(2 downto 0);
function slice(s: STD_LOGIC_VECTOR; u, l : natural) return STD_LOGIC_VECTOR is
alias sv : STD_LOGIC_VECTOR (s'length-1 downto 0) is s;
variable result : STD_LOGIC_VECTOR (u downto l);
begin
for i in result'range loop
result(i) := sv(i);
end loop;
return result;
end function;
begin
output <= slice(test & '0', 5, 3); -- test becomes 'to' range.
-- output still becomes "101"
end architecture;

VHDL Vector Array

I am attempting to create an array of vectors in VHDL however I am getting an error in modelsim.
I have:
type read_data_array is array (0 to 73) of std_logic_vector(7 downto 0);
signal reg_data_stream : read_data_array;
I store data into the array by:
reg_data_stream(counter) <= read_data;
"read_data" is that of std_logic_vector(7 downto 0) and "counter" is a basic counter that increments from 0.
To index an array or a vector, VHDL expects an integer. If counter is a std_logic_vector, try:
to_integer(unsigned(counter)) <= read_data;

VHDL multiple std_logic_vector to one large std_logic_vector

I have four std_logic_vectors (15 downto 0) and want to stack them into a std_logic_vector (63 downt 0) so fare I have found one way of doing it but is it the correct way or is there a more optimal and correct way to do it?
signal slv16_1,slv16_2,slv16_3,slv16_4 : std_logic_vector(15 downto 0);
signal slv64 : std_logic_vector(63 downto 0);
slv64(15 downto 0) <= slv16_1;
slv64(31 downto 16) <= slv16_2;
slv64(47 downto 32) <= slv16_3;
slv64(63 downto 48) <= slv16_4;
An easy way to accomplish this is to use the concatenation operator &. It achieves the same thing you did above, but with less code required.
slv64 <= slv16_4 & slv16_3 & slv16_2 & slv16_1;
Since the source vectors have unique names, I don't see a way to automate this. What you might be able to try is to never use the 16-bit vectors, and instead use slices of the larger 64 bit vector. So instead of an assignment like this:
slv16_1 <= "0101110000111010";
Use
slv64(15 downto 0) <= "0101110000111010";
Or instead of an entity instantiation where you connect slv16_2 like this:
output_port => slv16_2,
Use
output_port => slv64(31 downto 16),
I would really need to see more of your code to understand what might work best, but my basic answer is 'use the larger vector in the first place'.
If you can't do this for some reason, an alternative would be to declare your 16-bit vectors as an array of arrays:
type slv16_array_type is array (integer range <>) of std_logic_vector(15 downto 0);
signal slv16_array : slv16_array_type(3 downto 0);
You could then assign to the elements like this:
slv16_array(0) <= "0101";
You could combine the elements of this type with a generate loop:
slv16_combine : for i in 0 to 3 generate
slv64((16*(i+1))-1 downto 16*i) <= slv16_array(i);
end generate;
VHDL guide says that this one should work:
slv64 <= (slv16_4, slv16_3, slv16_2, slv16_1);

How to multiply by 2 a 32 bit signed std_logic_vector in VHDL

We have a type which is an array of 32 bit "std_logic_vector" of size 3, which is defined in the following way:
subtype scalar is std_logic_vector(31 downto 0);
type vector_nd is array (natural range <>) of scalar;
subtype vector_3d is vector_nd(2 downto 0);
We have a signal of type "vector_3d" which we want to multiply by 2 and put the result in a signal of type "scalar":
signal v_normal_out_sig := vector_3d;
signal mult1_in1_sig := scalar;
--...
mult1_in1_sig <= 2*signed(v_normal_out_sig(0)) when cau_state = st_cycle18;
When we compile it we get the error:
No feasible entries for infix operator "*".
What is the right way to implement what we want? We are using the following libraries:
ieee.std_logic_1164.all
ieee.std_logic_arith.all
ieee.std_logic_unsigned.all
What we did eventually is the fallowing:
mult1_in1_sig <= v_normal_out_sig(0)(31) & v_normal_out_sig(0)(29 downto 0) & '0' when cau_state = st_cycle18;
And test gave the right results for both positive and negative numbers.

Resources