ツリータイプ加算器のパラメタライズ

pp.315-318

絶対差の和(マンハッタン距離)を求める -でパラメタライズできていなかったツリータイプ加算器をパラメタライズする。

ここでは7ビット、10本を加算する。4レイヤーの加算が必要なので出力を7+4=11ビットにしてオーバーフローを防ぐ。

library ieee;
use ieee.numeric_std.all;
package user_defined_type_pkg is
    type signed_vector is array (natural range <>) of signed;
end package;

library ieee;
use ieee.numeric_std.all;
use ieee.math_real.all;
use work.user_defined_type_pkg.all;

entity adder_array_generic_tree is
    generic(
        NUM_INPUTS: natural := 10;
        NUM_BITS  : natural :=  7
       --NUM_LAYERS: natural :=  4 -- integer(ceil(log2(real(NUM_INPUTS))))
    );
    port(
       --x: in signed_vector(0 to NUM_INPUTS - 1)(NUM_BITS - 1 downto 0);
        x: in signed_vector(0 to 10 - 1)(7 - 1 downto 0);
       --sum: out signed(NUM_BITS + NUM_LAYERS - 1 downto 0);
        sum: out signed(7 + 4 - 1 downto 0)
    );
end entity;

architecture rtl of adder_array_generic_tree is
    constant LAYERS       : natural := integer(ceil(log2(real(NUM_INPUTS))));
    constant PSEUDO_INPUTS: natural := 2**LAYERS; -- コードが組みやすいよう、入力ポートの本数を2**加算レイヤー数とする。
    alias    EXTRA_BITS   : natural is LAYERS;
begin
    process(all)
        /*
       計算経過を結果を入れておくための排列を宣言する。
       ここでは7ビット、10本を加算するので、
       11ビット(=入力7ビット+加算レイヤー数)、16本(実際は10本であるが2**加算レイヤー数にしておく)の排列を宣言する。
       */
        variable accum: signed_vector(0 to PSEUDO_INPUTS - 1)(NUM_BITS + EXTRA_BITS - 1 downto 0);
    begin
       -- まず入力を全部11ビットに拡張しておく。
        for i in 0 to NUM_INPUTS - 1 loop
            accum(i) := resize(x(i), NUM_BITS + EXTRA_BITS);
        end loop;
        
       -- ほかの要素は全部0にしておく。
        accum(NUM_INPUTS to PSEUDO_INPUTS - 1) := (others => (others => '0'));

        /*
       ツリータイプで加算する。
       まず、
       [0]行+[1]行を[0]行に入れる。
       [2]行+[3]行を[1]行に入れる。
       ...
       [14]行+[15]行を[7]行に入れる。
       
       さらに、
       [0]行+[1]行を[0]行に入れる。
       [2]行+[3]行を[1]行に入れる。
       ...
       [6]行+[7]行を[3]行に入れる。
       
       さらに、
       [0]行+[1]行を[0]行に入れる。
       [2]行+[3]行を[1]行に入れる。
       
       最後に、
       [0]行+[1]行を[0]行に入れる。
       */
        for j in 1 to LAYERS loop
            for i in 0 to PSEUDO_INPUTS/(2**j) - 1 loop
                accum(i) := accum(2*i) + accum(2*i + 1);
            end loop;
        end loop;

        sum <= accum(0);
    end process;
end architecture;

下のように配線して動作を確認する。
f:id:ti-nspire:20210422101631p:plain:w500

今、20+10+3+3+3+3+3+3+3+3=54 (0b11_0110)を計算している。
f:id:ti-nspire:20210422101944j:plain:w500

入力本数を(2**レイヤー数)本に変えてコードを組んだがコンパイラーによって最適化された。
f:id:ti-nspire:20210422100918p:plain:w700