I have a datain as an std_logic_vector and i want fill a matrix with datain's bits and then display it.
How can i fill and display the matrix ?
Here is my code:
signal datain : std_logic_vector(39 downto 0) := "1111011101100110011001010110011001100110";
for i1 in 1 to 5 loop
for j1 in 1 to 8 loop
for j2 in datain'range loop
mat1(i1,j1)<=datain(j2);
end loop;
end loop;
end loop;
------- display the matrix
for i2 in 1 to 5 loop
for i3 in 1 to 8 loop
for i4 in dataout'range loop
dataout(i4) <= mat1(i2,i3);
end loop;
end loop;
end loop;
Thank you,
First we construct a Minimal, Complete and Verifiable example from your code snippets:
library ieee;
use ieee.std_logic_1164.all;
entity abir is
end entity;
architecture foo of abir is
type mat_type is array (1 to 5, 1 to 8) of std_logic;
signal mat1: mat_type;
signal datain : std_logic_vector(39 downto 0) :=
"1111011101100110011001010110011001100110";
signal dataout: std_logic_vector (39 downto 0); -- MISSING
-- this function is predefined in VHDL -2008:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
INITIALIZE_MATRIX:
process -- (datain)
begin
for i1 in 1 to 5 loop
for j1 in 1 to 8 loop
for j2 in datain'range loop
mat1(i1,j1)<=datain(j2);
end loop;
end loop;
end loop;
wait; -- Do only once, depends on the initial value of datain
end process; -- the wait statement can be removed if you add sensitivity
------- display the matrix
MATRIX_T0_DATAOUT:
process (mat1)
begin
for i2 in 1 to 5 loop
for i3 in 1 to 8 loop
for i4 in dataout'range loop
dataout(i4) <= mat1(i2,i3);
end loop;
end loop;
end loop;
end process;
DISPLAY_DATAOUT:
process -- (dataout)
begin -- wait statements so only disply valid datout
wait for 0 ns; -- first delta cycle all 'U's (dataout uninitialized)
wait for 0 ns; -- second delta cycle all 'U's (mat1 uninitialized)
report LF &
HT & "datain = " & to_string(datain) & LF &
HT & "dataout = " & to_string(dataout);
wait on dataout;
end process;
end architecture;
The function to_string is predefined in VHDL -2008, this MCVE should work with tools compliant earlier revisions of the VHDL standard.
It's specific to demonstrating your code. It gives:
ghdl -a abir.vhdl
ghdl -e abir
ghdl -r abir
abir.vhdl:58:9:@0ms:(report note):
datain = 1111011101100110011001010110011001100110
dataout = 0000000000000000000000000000000000000000
So there's something wrong with your nested loops (you can also verify this with a waveform viewer to determine mat1 is indeed all '0's).
So the cause of this is the very inner loops. With datain you assign each element of matrix mat1(i,j) N times where N is the length of datain (range of j2). With dataout you assign each indexed element of dataout (i4) every matrix element of mat(i2,i3).
So is it possible to have three loops performing these assignments?
Well, no.
In the INITIALIZE_MATRIX process every (i,j) location of mat1 was overwritten with all the index values of datain. Only the last one took affect. This filled the matrix with all '0's.
In the MATRIX_TO_DATAOUT process all the dataout indexes were 'scheduled' to have the last mat1(i2,i3) value of each i3 loop iteration, settling on the last loop iteration value of i2 and i3, a '0'.
We can modify the two sets of loops to decrement j2 or i4 as variables directly (the ranges of datain and dataout are in in descending order):
INITIALIZE_MATRIX:
process -- (datain)
variable j2: natural range datain'range;
begin
j2 := datain'LEFT; -- so the process can execute again.
for i1 in 1 to 5 loop
for j1 in 1 to 8 loop
-- for j2 in datain'range loop
mat1(i1,j1) <= datain(j2);
if j2 /= datain'RIGHT then
j2 := j2 - 1; -- datain has descending range
end if;
-- end loop;
end loop;
end loop;
wait; -- Do only once, depends on the initial value of datain
end process; -- the wait statement can be removed if you add sensitivity
------- display the matrix
MATRIX_T0_DATAOUT:
process (mat1)
variable i4: natural range dataout'range;
begin
i4 := dataout'LEFT; -- so the process can execute again
for i2 in 1 to 5 loop
for i3 in 1 to 8 loop
-- for i4 in dataout'range loop
dataout(i4) <= mat1(i2,i3);
if i4 /= dataout'RIGHT then
i4 := i4 - 1; -- dataout has descending range
end if;
-- end loop;
end loop;
end loop;
end process;
And that gives us:
abir.vhdl:68:9:@0ms:(report note):
datain = 1111011101100110011001010110011001100110
dataout = 1111011101100110011001010110011001100110
Where we find dataout matches datain. (A good thing.)
So the issue was the three nested loops in each process were incorrect. We wanted to manage the pointers to the input and output arrays separately.
We also manage the assignments to the variables j2 or i4 to prevent a bounds violation using if statements to prevent j2 or i4 being decremented when the variable assignment would be out of the value range of the variable. A bounds check failure on assignment would abort the simulation.
Note that signal assignment results in a value being written to a projected output waveform (a queue). Signal updates don't occur before any pending process has run and suspended. There's only one value for any time in the projected output waveform. (including the current simulation time).
These two modified processes could be used as the basis of conversion functions:
architecture fum of abir is
type mat_type is array (1 to 5, 1 to 8) of std_logic;
signal mat1: mat_type;
signal datain : std_logic_vector(39 downto 0) :=
"1111011101100110011001010110011001100110";
signal dataout: std_logic_vector (39 downto 0); -- MISSING
-- this function is predefined in VHDL -2008:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
function to_matrix (inp: std_logic_vector) return mat_type is
alias input: std_logic_vector(0 to inp'length - 1) is inp; -- ascending
variable mat: mat_type;
variable inptr: natural range 0 to inp'length;
begin
assert input'length = mat'length(1) * mat'length(2)
report LF &
"to_matrix call, input length (" &
integer'image(inp'length) & ") " &
"/= " & integer'image( mat'length(1) * mat'length(2))
severity FAILURE;
for i in mat'range(1) loop -- first dimension
for j in mat'range(2) loop -- second dimension
mat(i,j) := input(inptr);
inptr := inptr + 1; -- inptr range allows last increment
end loop;
end loop;
return mat;
end function;
function to_std_logic_vector (mat: mat_type) return std_logic_vector is
variable retval:
std_logic_vector(0 to mat'length(1) * mat'length(2) - 1);
variable outptr: natural range 0 to retval'length;
begin
for i in mat'range(1) loop -- first dimension
for j in mat'range(2) loop -- second dimension
retval(outptr) := mat(i,j);
outptr := outptr + 1; -- outptr range allows last increment
end loop;
end loop;
return retval;
end function;
begin
INITIALIZE_MATRIX:
mat1 <= to_matrix(datain);
MATRIX_T0_DATAOUT:
dataout <= to_std_logic_vector(mat1);
DISPLAY_DATAOUT:
process -- (dataout)
begin -- wait statements so only disply valid datout
wait for 0 ns; -- first delta cycle all 'U's (dataout uninitialized)
wait for 0 ns; -- second delta cycle all 'U's (mat1 uninitialized)
report LF &
HT & "datain = " & to_string(datain) & LF &
HT & "dataout = " & to_string(dataout);
wait for 1 ns;
wait on dataout;
end process;
end architecture;
The two functions are dependent only on the matrix type declaration. You can change the mat_type
declaration without having to modify declarations or the any of the sequence of statements found in the functions.
The new architecture with the to_matrix[std_logic_vector return mat_type]
and to_std_logic_vector[mat_type return std_logic_vector]
function calls provides the same answer as the MCVE with the corrected process statements.