Search code examples
vhdl

VHDL - AND variable number of bits


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;

Solution

  • 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)
    %: