diff --git a/libraries/technology/ip_arria10/complex_mult_rtl_canonical/hdllib.cfg b/libraries/technology/ip_arria10/complex_mult_rtl_canonical/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..67ba589530d4341c0d5c4a1f612502fa4ee51d5b --- /dev/null +++ b/libraries/technology/ip_arria10/complex_mult_rtl_canonical/hdllib.cfg @@ -0,0 +1,17 @@ +hdl_lib_name = ip_arria10_complex_mult_rtl_canonical +hdl_library_clause_name = ip_arria10_complex_mult_rtl_lib_canonical +hdl_lib_uses_synth = +hdl_lib_uses_sim = +hdl_lib_technology = #ip_arria10 This file is also used for arria10_e3sge3 and arria10_e1sg + +synth_files = + ip_arria10_complex_mult_rtl_canonical.vhd + +test_bench_files = + + +[modelsim_project_file] + + +[quartus_project_file] + diff --git a/libraries/technology/ip_arria10/complex_mult_rtl_canonical/ip_arria10_complex_mult_rtl_canonical.vhd b/libraries/technology/ip_arria10/complex_mult_rtl_canonical/ip_arria10_complex_mult_rtl_canonical.vhd new file mode 100644 index 0000000000000000000000000000000000000000..53510d0d42fdcdc5900b194173f1849f03b26720 --- /dev/null +++ b/libraries/technology/ip_arria10/complex_mult_rtl_canonical/ip_arria10_complex_mult_rtl_canonical.vhd @@ -0,0 +1,274 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2018 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Authors: +-- . Daniel van der Schuur +-- Purpose: +-- . RTL complex multiplier, canonical version (3 simple multipliers). +-- Description: +-- . re = ((ar+ai)*(br-bi))+(ar*bi-ai*br) +-- im = ar*bi+ai*br +-- Remark: +-- . g_conjugate_b is not supported! + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; + +ENTITY ip_arria10_complex_mult_rtl_canonical IS + GENERIC ( + g_in_a_w : POSITIVE; + g_in_b_w : POSITIVE; + g_out_p_w : POSITIVE; -- default use g_out_p_w = g_in_a_w+g_in_b_w = c_prod_w +-- g_conjugate_b : BOOLEAN := FALSE; + g_pipeline_input : NATURAL := 1; -- 0 or 1 + g_pipeline_product : NATURAL := 0; -- 0 or 1 + g_pipeline_adder : NATURAL := 1; -- 0 or 1 + g_pipeline_output : NATURAL := 1 -- >= 0 + ); + PORT ( + rst : IN STD_LOGIC := '0'; + clk : IN STD_LOGIC; + clken : IN STD_LOGIC := '1'; + in_ar : IN STD_LOGIC_VECTOR(g_in_a_w-1 DOWNTO 0); + in_ai : IN STD_LOGIC_VECTOR(g_in_a_w-1 DOWNTO 0); + in_br : IN STD_LOGIC_VECTOR(g_in_b_w-1 DOWNTO 0); + in_bi : IN STD_LOGIC_VECTOR(g_in_b_w-1 DOWNTO 0); + result_re : OUT STD_LOGIC_VECTOR(g_out_p_w-1 DOWNTO 0); + result_im : OUT STD_LOGIC_VECTOR(g_out_p_w-1 DOWNTO 0) + ); +END ip_arria10_complex_mult_rtl_canonical; + +ARCHITECTURE str OF ip_arria10_complex_mult_rtl_canonical IS + + FUNCTION RESIZE_NUM(s : SIGNED; w : NATURAL) RETURN SIGNED IS + BEGIN + -- extend sign bit or keep LS part + IF w>s'LENGTH THEN + RETURN RESIZE(s, w); -- extend sign bit + ELSE + RETURN SIGNED(RESIZE(UNSIGNED(s), w)); -- keep LSbits (= vec[w-1:0]) + END IF; + END; + + FUNCTION largest(n, m : INTEGER) RETURN INTEGER IS + BEGIN + IF n > m THEN + RETURN n; + ELSE + RETURN m; + END IF; + END; + + ----------------------------------------------------------------------------- + -- Multiply / add output signals + -- . re = ((ar+ai)*(br-bi))+(ar*bi-ai*br) + -- im = ar*bi+ai*br + ----------------------------------------------------------------------------- + CONSTANT c_sum_ar_ai_w : NATURAL := g_in_a_w+1; -- sum_ar_ai + CONSTANT c_sum_br_bi_w : NATURAL := g_in_b_w+1; -- sum_br_bi + CONSTANT c_prod_w : NATURAL := g_in_a_w+g_in_b_w; -- prod_ar_bi, prod_ai_br + CONSTANT c_sum_prod_w : NATURAL := c_prod_w+1; -- sum_prod_ar_bi_prod_ai_br + CONSTANT c_prod_sum_w : NATURAL := c_sum_ar_ai_w+c_sum_br_bi_w; -- prod_sum_ar_ai_sum_br_bi + CONSTANT c_sum_im_w : NATURAL := c_prod_w+1; -- sum_im + CONSTANT c_sum_re_w : NATURAL := largest(c_sum_prod_w, c_prod_sum_w)+1; -- sum_re + + SIGNAL sum_ar_ai : SIGNED(c_sum_ar_ai_w-1 DOWNTO 0); -- ar+ai : used in re + SIGNAL sum_br_bi : SIGNED(c_sum_br_bi_w-1 DOWNTO 0); -- br-bi : used in re + SIGNAL sum_prod_ar_bi_prod_ai_br : SIGNED(c_sum_prod_w-1 DOWNTO 0); -- ar*bi-ai*br : used in re + SIGNAL sum_im : SIGNED(c_sum_im_w-1 DOWNTO 0); -- ar*bi+ai*br : im + SIGNAL sum_re : SIGNED(c_sum_re_w-1 DOWNTO 0); -- ((ar+ai)*(br-bi))+(ar*bi-ai*br) : re + + SIGNAL prod_ar_bi : SIGNED(c_prod_w-1 DOWNTO 0); -- ar*bi : used in re and im + SIGNAL prod_ai_br : SIGNED(c_prod_w-1 DOWNTO 0); -- ai*br : used in re and im + SIGNAL prod_sum_ar_ai_sum_br_bi : SIGNED(c_prod_sum_w-1 DOWNTO 0); -- (ar+ai)*(br-bi) : used in re + + ----------------------------------------------------------------------------- + -- register signals + ----------------------------------------------------------------------------- + SIGNAL ar : SIGNED(g_in_a_w-1 DOWNTO 0); + SIGNAL ai : SIGNED(g_in_a_w-1 DOWNTO 0); + SIGNAL br : SIGNED(g_in_b_w-1 DOWNTO 0); + SIGNAL bi : SIGNED(g_in_b_w-1 DOWNTO 0); + + SIGNAL nxt_ar : SIGNED(g_in_a_w-1 DOWNTO 0); + SIGNAL nxt_ai : SIGNED(g_in_a_w-1 DOWNTO 0); + SIGNAL nxt_br : SIGNED(g_in_b_w-1 DOWNTO 0); + SIGNAL nxt_bi : SIGNED(g_in_b_w-1 DOWNTO 0); + + SIGNAL reg_ar : SIGNED(g_in_a_w-1 DOWNTO 0); + SIGNAL reg_ai : SIGNED(g_in_a_w-1 DOWNTO 0); + SIGNAL reg_br : SIGNED(g_in_b_w-1 DOWNTO 0); + SIGNAL reg_bi : SIGNED(g_in_b_w-1 DOWNTO 0); + + SIGNAL nxt_sum_ar_ai : SIGNED(c_sum_ar_ai_w-1 DOWNTO 0); + SIGNAL nxt_sum_br_bi : SIGNED(c_sum_br_bi_w-1 DOWNTO 0); + SIGNAL nxt_sum_prod_ar_bi_prod_ai_br : SIGNED(c_sum_prod_w-1 DOWNTO 0); + SIGNAL nxt_sum_im : SIGNED(c_sum_im_w-1 DOWNTO 0); + SIGNAL nxt_sum_re : SIGNED(c_sum_re_w-1 DOWNTO 0); + + SIGNAL nxt_prod_ar_bi : SIGNED(c_prod_w-1 DOWNTO 0); + SIGNAL nxt_prod_ai_br : SIGNED(c_prod_w-1 DOWNTO 0); + SIGNAL nxt_prod_sum_ar_ai_sum_br_bi : SIGNED(c_prod_sum_w-1 DOWNTO 0); + + SIGNAL reg_sum_ar_ai : SIGNED(c_sum_ar_ai_w-1 DOWNTO 0); + SIGNAL reg_sum_br_bi : SIGNED(c_sum_br_bi_w-1 DOWNTO 0); + SIGNAL reg_sum_prod_ar_bi_prod_ai_br : SIGNED(c_sum_prod_w-1 DOWNTO 0); + SIGNAL reg_sum_im : SIGNED(c_sum_im_w-1 DOWNTO 0); + SIGNAL reg_sum_re : SIGNED(c_sum_re_w-1 DOWNTO 0); + + SIGNAL reg_prod_ar_bi : SIGNED(c_prod_w-1 DOWNTO 0); + SIGNAL reg_prod_ai_br : SIGNED(c_prod_w-1 DOWNTO 0); + SIGNAL reg_prod_sum_ar_ai_sum_br_bi : SIGNED(c_prod_sum_w-1 DOWNTO 0); + + SIGNAL nxt_result_re : SIGNED(g_out_p_w-1 DOWNTO 0); + SIGNAL nxt_result_im : SIGNED(g_out_p_w-1 DOWNTO 0); + + SIGNAL reg_result_re : SIGNED(g_out_p_w-1 DOWNTO 0); + SIGNAL reg_result_im : SIGNED(g_out_p_w-1 DOWNTO 0); + +BEGIN + + ------------------------------------------------------------------------------ + -- Registers + ------------------------------------------------------------------------------ + + -- Put all potential registers in a single process for optimal DSP inferrence + -- Use rst only if it is supported by the DSP primitive, else leave it at '0' + p_reg : PROCESS (rst, clk) + BEGIN + IF rising_edge(clk) THEN + IF rst='1' THEN + reg_ar <= (OTHERS=>'0'); + reg_ai <= (OTHERS=>'0'); + reg_br <= (OTHERS=>'0'); + reg_bi <= (OTHERS=>'0'); + + reg_sum_ar_ai <= (OTHERS=>'0'); + reg_sum_br_bi <= (OTHERS=>'0'); + reg_sum_prod_ar_bi_prod_ai_br <= (OTHERS=>'0'); + reg_sum_im <= (OTHERS=>'0'); + reg_sum_re <= (OTHERS=>'0'); + + reg_prod_ar_bi <= (OTHERS=>'0'); + reg_prod_ai_br <= (OTHERS=>'0'); + reg_prod_sum_ar_ai_sum_br_bi <= (OTHERS=>'0'); + ELSIF clken='1' THEN + reg_ar <= nxt_ar; + reg_ai <= nxt_ai; + reg_br <= nxt_br; + reg_bi <= nxt_bi; + + reg_sum_ar_ai <= nxt_sum_ar_ai; + reg_sum_br_bi <= nxt_sum_br_bi; + reg_sum_prod_ar_bi_prod_ai_br <= nxt_sum_prod_ar_bi_prod_ai_br; + reg_sum_im <= nxt_sum_im; + reg_sum_re <= nxt_sum_re; + + reg_prod_ar_bi <= nxt_prod_ar_bi; + reg_prod_ai_br <= nxt_prod_ai_br; + reg_prod_sum_ar_ai_sum_br_bi <= nxt_prod_sum_ar_ai_sum_br_bi; + END IF; + END IF; + END PROCESS; + + ------------------------------------------------------------------------------ + -- Inputs + ------------------------------------------------------------------------------ + nxt_ar <= SIGNED(in_ar); + nxt_ai <= SIGNED(in_ai); + nxt_br <= SIGNED(in_br); + nxt_bi <= SIGNED(in_bi); + + no_input_reg : IF g_pipeline_input=0 GENERATE -- wired + ar <= nxt_ar; + ai <= nxt_ai; + br <= nxt_br; + bi <= nxt_bi; + END GENERATE; + + gen_input_reg : IF g_pipeline_input>0 GENERATE -- register input + ar <= reg_ar; + ai <= reg_ai; + br <= reg_br; + bi <= reg_bi; + END GENERATE; + + ------------------------------------------------------------------------------ + -- Sums + ------------------------------------------------------------------------------ + nxt_sum_ar_ai <= RESIZE_NUM(ar, c_sum_ar_ai_w) + ai; + nxt_sum_br_bi <= RESIZE_NUM(br, c_sum_br_bi_w) + bi; + nxt_sum_prod_ar_bi_prod_ai_br <= RESIZE_NUM(prod_ar_bi, c_prod_sum_w) + prod_ai_br; + nxt_sum_re <= RESIZE_NUM(prod_sum_ar_ai_sum_br_bi, c_prod_sum_w), sum_prod_ar_bi_prod_ai_br; + nxt_sum_im <= RESIZE_NUM(prod_ai_br, c_sum_im_w) + prod_ar_bi; + + no_adder_reg : IF g_pipeline_adder=0 GENERATE -- wired + sum_ar_ai <= nxt_sum_ar_ai; + sum_br_bi <= nxt_sum_br_bi; + sum_prod_ar_bi_prod_ai_br <= nxt_sum_prod_ar_bi_prod_ai_br; + sum_re <= nxt_sum_re; + sum_im <= nxt_sum_im; + END GENERATE; + gen_adder_reg : IF g_pipeline_adder>0 GENERATE -- register + sum_ar_ai <= reg_sum_ar_ai; + sum_br_bi <= reg_sum_br_bi; + sum_prod_ar_bi_prod_ai_br <= reg_sum_prod_ar_bi_prod_ai_br; + sum_re <= reg_sum_re; + sum_im <= reg_sum_im; + END GENERATE; + + ------------------------------------------------------------------------------ + -- Products + ------------------------------------------------------------------------------ + nxt_prod_ar_bi <= ar * bi; + nxt_prod_ai_br <= ai * br; + nxt_prod_sum_ar_ai_sum_br_bi <= sum_ar_ai * sum_br_bi; + + no_product_reg : IF g_pipeline_product=0 GENERATE -- wired + prod_ar_bi <= nxt_prod_ar_bi; + prod_ai_br <= nxt_prod_ai_br; + prod_sum_ar_ai_sum_br_bi <= nxt_prod_sum_ar_ai_sum_br_bi; + + END GENERATE; + gen_product_reg : IF g_pipeline_product>0 GENERATE -- register + prod_ar_bi <= reg_prod_ar_bi; + prod_ai_br <= reg_prod_ai_br; + prod_sum_ar_ai_sum_br_bi <= reg_prod_sum_ar_ai_sum_br_bi; + END GENERATE; + + ------------------------------------------------------------------------------ + -- Result sum after optional rounding + ------------------------------------------------------------------------------ + + nxt_result_re <= RESIZE_NUM(sum_re, g_out_p_w); + nxt_result_im <= RESIZE_NUM(sum_im, g_out_p_w); + + no_result_reg : IF g_pipeline_output=0 GENERATE -- wired + result_re <= STD_LOGIC_VECTOR(nxt_result_re); + result_im <= STD_LOGIC_VECTOR(nxt_result_im); + END GENERATE; + gen_result_reg : IF g_pipeline_output>0 GENERATE -- register + result_re <= STD_LOGIC_VECTOR(reg_result_re); + result_im <= STD_LOGIC_VECTOR(reg_result_im); + END GENERATE; + +END ARCHITECTURE; diff --git a/libraries/technology/mult/tech_complex_mult.vhd b/libraries/technology/mult/tech_complex_mult.vhd index 7b1368e19f3a4422d4777bb4f1f357ed3d3aebbf..82975e83418293f02b81b5045c8d1ccaa57fbe09 100644 --- a/libraries/technology/mult/tech_complex_mult.vhd +++ b/libraries/technology/mult/tech_complex_mult.vhd @@ -33,7 +33,7 @@ LIBRARY ip_stratixiv_mult_lib; LIBRARY ip_arria10_complex_mult_altmult_complex_150; LIBRARY ip_arria10_e1sg_complex_mult_altmult_complex_170; LIBRARY ip_arria10_complex_mult_rtl_lib; - +LIBRARY ip_arria10_complex_mult_rtl_canonical_lib; ENTITY tech_complex_mult IS GENERIC ( @@ -165,6 +165,7 @@ begin result_im <= RESIZE_SVEC(mult_im, g_out_p_w); END GENERATE; + -- RTL variant is the same for unb2, unb2a and unb2b gen_ip_arria10_rtl : IF (g_sim=FALSE OR (g_sim=TRUE AND g_sim_level=0)) AND ((g_technology=c_tech_arria10 OR g_technology=c_tech_arria10_e3sge3 OR g_technology=c_tech_arria10_e1sg ) AND g_variant="RTL") GENERATE @@ -192,6 +193,32 @@ begin ); END GENERATE; + gen_ip_arria10_rtl_canonical : IF (g_sim=FALSE OR (g_sim=TRUE AND g_sim_level=0)) AND + ((g_technology=c_tech_arria10 OR g_technology=c_tech_arria10_e3sge3 OR g_technology=c_tech_arria10_e1sg ) AND g_variant="RTL_C") GENERATE + u0 : ip_arria10_complex_mult_rtl_canonical + GENERIC MAP( + g_in_a_w => g_in_a_w, + g_in_b_w => g_in_b_w, + g_out_p_w => g_out_p_w, +-- g_conjugate_b => g_conjugate_b, -- NOT SUPPORTED + g_pipeline_input => g_pipeline_input, + g_pipeline_product => g_pipeline_product, + g_pipeline_adder => g_pipeline_adder, + g_pipeline_output => g_pipeline_output + ) + PORT MAP( + rst => rst, + clk => clk, + clken => clken, + in_ar => in_ar, + in_ai => in_ai, + in_br => in_br, + in_bi => in_bi, + result_re => result_re, + result_im => result_im + ); + END GENERATE; + gen_ip_arria10_e1sg_ip : IF (g_sim=FALSE OR (g_sim=TRUE AND g_sim_level=0)) AND (g_technology=c_tech_arria10_e1sg AND g_variant="IP") GENERATE