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;
下のように配線して動作を確認する。
今、20+10+3+3+3+3+3+3+3+3=54 (0b11_0110)を計算している。
入力本数を(2**レイヤー数)本に変えてコードを組んだがコンパイラーによって最適化された。