I have a w*y-bit width std_logic_vector
named matrix
where w and y are integers. I want to have y-bit width std_logic_vector
called output
that its bits are concurrently assigned to AND of w bits of matrix
elements.
For example, w=5 y=3:
output(2) <= matrix(14) and matrix(13) and matrix(12) and matrix(11) and matrix(10);
output(1) <= matrix(9) and matrix(8) and matrix(7) and matrix(6) and matrix(5);
output(0) <= matrix(4) and matrix(3) and matrix(2) and matrix(1) and matrix(0);
In the example, you can see that output
is y-bit long which is 3, and each bit of the output
is assigned to AND of w-bits of matrix
which is 5.
Now, I want to write it with generics. I have tried to write it in two for..generate
loop but I cannot handle it. What should be in the right hand side of the output(i)
? It can also be implemented in another way, and I am very welcome to another ideas. It does not have to be in the way I thought.
library ieee;
use ieee.std_logic_1164.all;
entity module is
generic (
w : integer := 5; -- input width
y : integer := 3 -- output width
);
port (
matrix : in std_logic_vector(w * y - 1 downto 0); -- matrix
output : out std_logic_vector(y - 1 downto 0) -- output
);
end entity module;
architecture rtl of module is
begin -- architecture rtl
AND_FOR: for i in y - 1 downto 0 generate
AND_FOR2: for j in w - 1 downto 0 generate
output(i) <= ????;
end generate AND_FOR2;
end generate AND_FOR;
end architecture rtl;
The goal here is finding a way to describe slices with the range of elements in your assignments as inputs to a reduction AND using elaborated bounds in as few generate statements as possible.
Generate statements are attractive in providing static indexed names or slice names preserving synthesis eligibility. We don't have a way to elaborate different complexity (here length) expressions in VHDL which makes an AND reduction attractive. Depending on synthesis tools you may be 'encouraged' to use a preexisting function, such as AND_REDUCE
found in Synopsys package std_logic_misc.
In -2008 we can use a unitary AND (the reserved word and followed by an operand. In tools compliant to earlier revisions of the VHDL standard we can use a function call:
architecture rtl of module is
-- -2008 use unitary AND without parameter instead of call:
function reduce_and (inp: std_logic_vector) return std_logic is
variable retval: std_logic := '1';
begin
for i in inp'range loop
retval := retval and inp(i);
end loop;
return retval;
end function;
begin
AND_FOR:
for i in y - 1 downto 0 generate
output(i) <= reduce_and(matrix((i + 1) * w - 1 downto i * w));
end generate;
describe_outputs:
process
begin
report "matrix'range is (" & integer'image(matrix'left) &
" downto " & integer'image(matrix'right) & ")";
for i in y - 1 downto 0 loop
report "output(" & integer'image(i) & ") <= reduce_and(matrix(" &
integer'image((i + 1) * w - 1 ) & " downto " &
integer'image (i * w) & ")";
end loop;
wait;
end process;
end architecture;
A for generate statement will elaborate a block for each value of it's for generate parameter (here i). It's declared as a constant in the block declarative region. Both w and y are globally static generic constants and as a result the range of matrix is also globally static. This mostly means that using a generate statement like this results in synthesis eligible assignment statements.
The process statement labeled describe_outputs
is added to demonstrate equivalency (the ability to algorithmically describe the elements being ANDed together) with your previous assignment statements because you haven't demonstrated a value for matrix and an expected result along with a testbench. The process can be eliminated.
As long as you use values for w
and x
that don't result in a null range or null slice this method should work with the hard coded direction (downto
).
Report statements are implementation dependent (with required 'header' information). Here shown for ghdl:
%: ghdl -a module.vhdl
%: ghdl -e module
%: ghdl -r module
module.vhdl:35:9:@0ms:(report note): matrix'range is (14 downto 0)
module.vhdl:38:13:@0ms:(report note): output(2) <= reduce_and(matrix(14 downto 10)
module.vhdl:38:13:@0ms:(report note): output(1) <= reduce_and(matrix(9 downto 5)
module.vhdl:38:13:@0ms:(report note): output(0) <= reduce_and(matrix(4 downto 0)
%: