Declare a variable number of signals with variable bitwidth in VHDL'93

后端 未结 2 1301
春和景丽
春和景丽 2021-01-27 06:44

I\'m trying to implement an generic adder tree similar to here. For storing the intermediate results, I need to declare a variable number of signals with variable bitwidth. For

相关标签:
2条回答
  • 2021-01-27 06:49

    Contrary to NiM's assertion that it's impossible to declare a variable amount of signals with increasing bitwidth and dependent on the number of input values in any version (revision) of VHDL, it is possible in -2008.

    The secret is to use component instantiation recursion with an input port whose type is an unbounded array with an element subtype indication provided in the object declaration. The number of inputs and their length can be changed (number of inputs down, element subtype length up) in successive recursion levels. The output port is of a constant width and is driven by the lowest level adder output.

    Defining an unbounded array definition with a deferred element subtype indication is not supported in -1993.

    This code hasn't been verified other than guaranteeing the lengths and numbers of levels work correctly. It uses unsigned arithmetic because the OP didn't specify otherwise. Resize is used to increase the adder result length.

    The report statements were used for debugging and can be removed (amazing how many simple errors you can make in something only mildly convoluted).

    library ieee;
    use ieee.std_logic_1164.all;
    
    package adder_tree_pkg is  
        function clog2 (n: positive) return natural;
        type input_array is array (natural range <>) of
                   std_logic_vector; --  -2008 unbounded array definition
        function isodd (n: positive) return natural;
    end package;
    
    package body adder_tree_pkg is
        function clog2 (n: positive) return natural is
            variable r: natural := 0;
            variable m: natural := n - 1;
        begin
            while m /= 0 loop
                r := r + 1; 
                m := m / 2;
            end loop;
            return r;
        end function clog2;
    
        function isodd (n: positive) return natural is
        begin
            if (n/2 * 2 < n) then
                return 1;
            else 
                return 0;
            end if;
        end function;
    end package body;
    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std_unsigned.all;
    
    use work.adder_tree_pkg.all;
    
    entity adder_tree_level is
        generic (
            constant INPUTS:  positive := 9;
            constant BITS:    positive := 8;
            constant LEVEL:   positive  := clog2(INPUTS);
            constant Y_OUT_LEN: positive := LEVEL + BITS
        );
        port (
            clk:    in  std_logic;
            rst_n:  in  std_logic;
            x_in:   in  input_array (INPUTS - 1 downto 0) (BITS - 1 downto 0);
            y_out:  out std_logic_vector (Y_OUT_LEN - 1 downto 0)
        );
    end entity;
    
    architecture foo of adder_tree_level is
        constant ODD_NUM_IN:    natural := isodd(INPUTS);
        constant NXT_INPS:  natural := INPUTS/2 + ODD_NUM_IN;
    
        signal x:           input_array (INPUTS - 1 downto 0) (BITS - 1 downto 0);
        signal nxt_x:       input_array (NXT_INPS - 1 downto 0)
                                        (BITS downto 0);
        constant NPAIRS:    natural  := (INPUTS)/2;
    begin
    INPUT_REGISTER:
        process (clk, rst_n)
    
        begin
            if rst_n = '0' then
                x <= (others =>(others => '0')); 
            elsif rising_edge (clk) then
                x <= x_in;
            end if;
        end process;
    
    ADDERS: 
        process (x)
        begin
            report "LEVEL = " & integer'image(LEVEL);
            report "y_out'length = " & integer'image(y_out'length);
            report "nxt_x(0)'length = " & integer'image(nxt_x(0)'length);
            for i in 0 to NPAIRS - 1 loop  -- odd out is x'high ('left)
                nxt_x(i) <= resize(x(i * 2), BITS + 1) + x(i * 2 + 1);
                report "i * 2 = " & integer'image (i * 2);
                report "i * 2 + 1 = " & integer'image (i * 2 + 1);
            end loop;
            if ODD_NUM_IN = 1 then
                report "x'left = " & integer'image(x'left);
                nxt_x(nxt_x'HIGH) <= resize(x(x'LEFT), BITS + 1);
            end if;
        end process;
    RECURSE:
        if LEVEL > 1 generate 
    NEXT_LEVEL:
            entity work.adder_tree_level
            generic map (
                INPUTS => NXT_INPS,
                BITS => BITS + 1,
                LEVEL => LEVEL - 1,
                Y_OUT_LEN => Y_OUT_LEN
            )
            port map (
                clk => clk,
                rst_n => rst_n,
                x_in => nxt_x,
                y_out => y_out
            );
        end generate;
    OUTPUT: 
       if LEVEL = 1 generate
    FINAL_OUTPUT:
            y_out <= nxt_x(0);
        end generate;
    end architecture;
    

    This example doesn't meet the criteria for answering Yes to the OP's question (which is a yes/no question) and simply refutes NiM's assertion that you can't do it in any version (revision) of VHDL.

    It's ports are inspired by the Pipelined Adder Tree VHDL code found by the image the OP linked.

    0 讨论(0)
  • 2021-01-27 07:01

    What you are asking for is not possible in any version of VHDL, v93 or otherwise. You can define a type inside a generate statement, but not use a generate within a type definition.

    Your initial solution is the way that I would do it personally - if targeting an FPGA using modern tools the unused MSBs at each stage will be optimised away during synthesis, so the resulting circuit is as you've described with no additional overhead (i.e. the tools are clever enough to know that adding two 8-bit numbers can never occupy more than 9 bits).

    0 讨论(0)
提交回复
热议问题