Skip to content
Snippets Groups Projects
Commit 96896f14 authored by Reinier van der Walle's avatar Reinier van der Walle
Browse files

Merge branch 'RTSD-182' into 'master'

Porting multipliers: mult, mult_add2, mult_add4, complex_mult, complex_mult_rtl, complex_mult_rtl_canonical for Intel Agilex 7

Closes RTSD-182

See merge request !361
parents a19db0b0 7ef493f2
No related branches found
No related tags found
1 merge request!361Porting multipliers: mult, mult_add2, mult_add4, complex_mult, complex_mult_rtl, complex_mult_rtl_canonical for Intel Agilex 7
Pipeline #61811 passed
Showing
with 3367 additions and 0 deletions
# ------------------------------------------------------------------------------
#
# Copyright 2023
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------
#
# Author: D.F. Brouwer
# Description:
# This file is based on generated file mentor/msim_setup.tcl.
# - the values for modelsim_search_libraries key in the hdllib.cfg follow from altera libraries vmap section in the msim_setup.tcl
# - vmap for the IP specific libraries and compile all IP source files into those libraries similar as in the msim_setup.tcl
# - replace QSYS_SIMDIR by IP_DIR
# - if the testbench is also generated with QSYS then only the IP_TBDIR files are needed, because these also contain the source files.
#vlib ./work/ ;# Assume library work already exist
set IP_DIR "$env(HDL_BUILD_DIR)/$env(BUILDSET)/qsys-generate/ip_agi027_xxxx_complex_mult/sim"
vmap altmult_complex_1910 ./work/
vcom "$IP_DIR/../altmult_complex_1910/sim/ip_agi027_xxxx_complex_mult_altmult_complex_1910_mvkwxpy.vhd" -work altmult_complex_1910
set IP_DIR "$env(HDL_BUILD_DIR)/$env(BUILDSET)/qsys-generate/ip_agi027_xxxx_complex_mult_27b/sim"
vcom "$IP_DIR/../altmult_complex_1910/sim/ip_agi027_xxxx_complex_mult_27b_altmult_complex_1910_fuab2ya.vhd" -work altmult_complex_1910
hdl_lib_name = ip_agi027_xxxx_altmult_complex_1910
hdl_library_clause_name = altmult_complex_1910
hdl_lib_uses_synth =
hdl_lib_uses_sim =
hdl_lib_technology = ip_agi027_xxxx
synth_files =
test_bench_files =
[modelsim_project_file]
modelsim_compile_ip_files =
$HDL_WORK/libraries/technology/ip_agi027_xxxx/altera_libraries/altmult_complex_1910/compile_ip.tcl
common: n_libs=9 lib_order=['technology', 'ip_agi027_xxxx_ram', 'tech_memory', 'ip_agi027_xxxx_fifo', 'tech_fifo', 'ip_agi027_xxxx_ddio', 'tech_iobuf', 'tst', 'common']
New test order: []
README.txt for $HDL_WORK/libraries/technology/ip_agi027_xxxx/complex_mult
1) Porting
2) IP component
3) Compilation, simulation and verification
4) Synthesis
5) Remarks
1) Porting
The complex_mult IP was ported manually from Quartus v19.4 for Arria10_e2sg to Quartus 23.2 for Agi027_xxxx by creating it in Quartus (Qsys) using
the same parameter settings.
2) IP component
The generated IPs are not kept in git repository, only the ip source files:
ip_agi027_xxxx_complex_mult.ip
ip_agi027_xxxx_complex_mult_27b.ip
Therefore first the IP needs to be generated using:
generate_ip_libs iwave
3) Compilation, simulation and verification
The generated IP also contains a msim_setup.tcl file that was used to manually create:
compile_ip.tcl
This compile_ip.tcl is in the hdllib.cfg and gets compiled before the other code.
4) Synthesis
No synthesis trials were done, because this will implicitely be done when the IP is used in a design. The QIP file:
ip_agi027_xxxx_complex_mult.qip
ip_agi027_xxxx_complex_mult_27b.qip
is included in the hdllib.cfg and contains what is needed to synthesize the IP.
5) Remarks
a) Use generated IP specific library clause name and IP specific lib uses sim
The generated ip_agi027_xxxx_<lib_name>.vhd uses an IP specific library name. Therefore the hdllib.cfg uses the IP
specific library as library clause name and, in addition, uses lib uses sim to make it known:
hdl_lib_name = ip_agi027_xxxx_<lib_name>
hdl_library_clause_name = ip_agi027_xxxx_<lib_name>_<ip_specific>
hdl_lib_uses_sim = ip_agi027_xxxx_<ip_specific>
b) When multiple IPs are generated, each utilizing the same IP function but with different settings, it results in the generation of the same
library name, containing a different .vhd file, as opposed to the previously used unique library names. This leads to issues. To address
this, shared libraries are combined within a single library with the IP-specific library name in the build directory when 'generate_ip_libs'
is used. Therefore, a directory is manually created in 'altera_libraries' with the IP-specific library name, containing three files:
'compile_ip.tcl', 'hdllib.cfg' and 'liborder'.
# ------------------------------------------------------------------------------
#
# Copyright 2023
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------
#
# Author: D.F. Brouwer
# Description:
# This file is based on generated file mentor/msim_setup.tcl.
# - the values for modelsim_search_libraries key in the hdllib.cfg follow from altera libraries vmap section in the msim_setup.tcl
# - vmap for the IP specific libraries and compile all IP source files into those libraries similar as in the msim_setup.tcl
# - replace QSYS_SIMDIR by IP_DIR
# - if the testbench is also generated with QSYS then only the IP_TBDIR files are needed, because these also contain the source files.
#vlib ./work/ ;# Assume library work already exist
set IP_DIR "$env(HDL_BUILD_DIR)/$env(BUILDSET)/qsys-generate/ip_agi027_xxxx_complex_mult/sim"
vcom "$IP_DIR/ip_agi027_xxxx_complex_mult.vhd"
set IP_DIR "$env(HDL_BUILD_DIR)/$env(BUILDSET)/qsys-generate/ip_agi027_xxxx_complex_mult_27b/sim"
vcom "$IP_DIR/ip_agi027_xxxx_complex_mult_27b.vhd"
hdl_lib_name = ip_agi027_xxxx_complex_mult
hdl_library_clause_name = ip_agi027_xxxx_complex_mult_altmult_complex_1910
hdl_lib_uses_synth =
hdl_lib_uses_sim = ip_agi027_xxxx_altmult_complex_1910
hdl_lib_technology = ip_agi027_xxxx
synth_files =
test_bench_files =
[modelsim_project_file]
modelsim_compile_ip_files =
$HDL_WORK/libraries/technology/ip_agi027_xxxx/complex_mult/compile_ip.tcl
[quartus_project_file]
quartus_qip_files =
$HDL_BUILD_DIR/<buildset_name>/qsys-generate/ip_agi027_xxxx_complex_mult/ip_agi027_xxxx_complex_mult.qip
$HDL_BUILD_DIR/<buildset_name>/qsys-generate/ip_agi027_xxxx_complex_mult_27b/ip_agi027_xxxx_complex_mult_27b.qip
[generate_ip_libs]
qsys-generate_ip_files =
ip_agi027_xxxx_complex_mult.ip
ip_agi027_xxxx_complex_mult_27b.ip
hdl_lib_name = ip_agi027_xxxx_complex_mult_rtl
hdl_library_clause_name = ip_agi027_xxxx_complex_mult_rtl_lib
hdl_lib_uses_synth =
hdl_lib_uses_sim =
hdl_lib_technology = #Similar to the complex_mult_rtl hdllib of arria10_e1sg, e2sg, e3sge3
synth_files =
ip_agi027_xxxx_complex_mult_rtl.vhd
test_bench_files =
[modelsim_project_file]
[quartus_project_file]
-- --------------------------------------------------------------------------
--
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- -------------------------------------------------------------------------
--
-- Author : D.F. Brouwer
-- Reference:
-- Copied from */technology/ip_arria10/complex_mult_rtl/ip_arria10_complex_mult_rtl.vhd.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
--
-- Function: Signed complex multiply
-- p = a * b when g_conjugate_b = FALSE
-- = (ar + j ai) * (br + j bi)
-- = ar*br - ai*bi + j ( ar*bi + ai*br)
--
-- p = a * conj(b) when g_conjugate_b = TRUE
-- = (ar + j ai) * (br - j bi)
-- = ar*br + ai*bi + j (-ar*bi + ai*br)
--
-- Architectures:
-- . rtl : uses RTL to have all registers in one clocked process
--
entity ip_agi027_xxxx_complex_mult_rtl 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_agi027_xxxx_complex_mult_rtl;
architecture str of ip_agi027_xxxx_complex_mult_rtl 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;
constant c_prod_w : natural := g_in_a_w + g_in_b_w;
constant c_sum_w : natural := c_prod_w + 1;
-- CONSTANT c_re_add_sub : STRING := sel_a_b(g_conjugate_b, "ADD", "SUB");
-- CONSTANT c_im_add_sub : STRING := sel_a_b(g_conjugate_b, "SUB", "ADD");
-- registers
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 reg_prod_ar_br : signed(c_prod_w - 1 downto 0); -- re
signal reg_prod_ai_bi : signed(c_prod_w - 1 downto 0);
signal reg_prod_ai_br : signed(c_prod_w - 1 downto 0); -- im
signal reg_prod_ar_bi : signed(c_prod_w - 1 downto 0);
signal reg_sum_re : signed(c_sum_w - 1 downto 0);
signal reg_sum_im : signed(c_sum_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);
-- combinatorial
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 nxt_prod_ar_br : signed(c_prod_w - 1 downto 0); -- re
signal nxt_prod_ai_bi : signed(c_prod_w - 1 downto 0);
signal nxt_prod_ai_br : signed(c_prod_w - 1 downto 0); -- im
signal nxt_prod_ar_bi : signed(c_prod_w - 1 downto 0);
signal nxt_sum_re : signed(c_sum_w - 1 downto 0);
signal nxt_sum_im : signed(c_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);
-- the active 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 prod_ar_br : signed(c_prod_w - 1 downto 0); -- re
signal prod_ai_bi : signed(c_prod_w - 1 downto 0);
signal prod_ai_br : signed(c_prod_w - 1 downto 0); -- im
signal prod_ar_bi : signed(c_prod_w - 1 downto 0);
signal sum_re : signed(c_sum_w - 1 downto 0);
signal sum_im : signed(c_sum_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_prod_ar_br <= (others => '0');
reg_prod_ai_bi <= (others => '0');
reg_prod_ai_br <= (others => '0');
reg_prod_ar_bi <= (others => '0');
reg_sum_re <= (others => '0');
reg_sum_im <= (others => '0');
reg_result_re <= (others => '0');
reg_result_im <= (others => '0');
elsif clken = '1' then
reg_ar <= nxt_ar; -- inputs
reg_ai <= nxt_ai;
reg_br <= nxt_br;
reg_bi <= nxt_bi;
reg_prod_ar_br <= nxt_prod_ar_br; -- products for re
reg_prod_ai_bi <= nxt_prod_ai_bi;
reg_prod_ai_br <= nxt_prod_ai_br; -- products for im
reg_prod_ar_bi <= nxt_prod_ar_bi;
reg_sum_re <= nxt_sum_re; -- sum
reg_sum_im <= nxt_sum_im;
reg_result_re <= nxt_result_re; -- result sum after optional register stage
reg_result_im <= nxt_result_im;
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;
------------------------------------------------------------------------------
-- Products
------------------------------------------------------------------------------
nxt_prod_ar_br <= ar * br; -- products for re
nxt_prod_ai_bi <= ai * bi;
nxt_prod_ai_br <= ai * br; -- products for im
nxt_prod_ar_bi <= ar * bi;
no_product_reg : if g_pipeline_product = 0 generate -- wired
prod_ar_br <= nxt_prod_ar_br;
prod_ai_bi <= nxt_prod_ai_bi;
prod_ai_br <= nxt_prod_ai_br;
prod_ar_bi <= nxt_prod_ar_bi;
end generate;
gen_product_reg : if g_pipeline_product > 0 generate -- register
prod_ar_br <= reg_prod_ar_br;
prod_ai_bi <= reg_prod_ai_bi;
prod_ai_br <= reg_prod_ai_br;
prod_ar_bi <= reg_prod_ar_bi;
end generate;
------------------------------------------------------------------------------
-- Sum
------------------------------------------------------------------------------
-- Re
-- . "ADD" for a*conj(b) : ar*br + ai*bi
-- . "SUB" for a*b : ar*br - ai*bi
gen_re_add : if g_conjugate_b generate
nxt_sum_re <= RESIZE_NUM(prod_ar_br, c_sum_w) + prod_ai_bi;
end generate;
gen_re_sub : if not g_conjugate_b generate
nxt_sum_re <= RESIZE_NUM(prod_ar_br, c_sum_w) - prod_ai_bi;
end generate;
-- Im
-- . "ADD" for a*b : ai*br + ar*bi
-- . "SUB" for a*conj(b) : ai*br - ar*bi
gen_im_add : if not g_conjugate_b generate
nxt_sum_im <= RESIZE_NUM(prod_ai_br, c_sum_w) + prod_ar_bi;
end generate;
gen_im_sub : if g_conjugate_b generate
nxt_sum_im <= RESIZE_NUM(prod_ai_br, c_sum_w) - prod_ar_bi;
end generate;
no_adder_reg : if g_pipeline_adder = 0 generate -- wired
sum_re <= nxt_sum_re;
sum_im <= nxt_sum_im;
end generate;
gen_adder_reg : if g_pipeline_adder > 0 generate -- register
sum_re <= reg_sum_re;
sum_im <= reg_sum_im;
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;
hdl_lib_name = ip_agi027_xxxx_complex_mult_rtl_canonical
hdl_library_clause_name = ip_agi027_xxxx_complex_mult_rtl_canonical_lib
hdl_lib_uses_synth =
hdl_lib_uses_sim =
hdl_lib_technology = #Similar to the complex_mult_rtl_canonical hdllib of arria10_e1sg, e2sg, e3sge3
synth_files =
ip_agi027_xxxx_complex_mult_rtl_canonical.vhd
test_bench_files =
[modelsim_project_file]
[quartus_project_file]
-- -----------------------------------------------------------------------------
--
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- -----------------------------------------------------------------------------
--
-- Author :
-- . D.F. Brouwer
-- 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!
-- Reference:
-- . Copied from */technology/ip_arria10/complex_mult_rtl_canonical/ip_arria10_complex_mult_rtl_canonical.vhd, authored by Daniel van der Schuur
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity ip_agi027_xxxx_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_agi027_xxxx_complex_mult_rtl_canonical;
architecture str of ip_agi027_xxxx_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;
hdl_lib_name = ip_agi027_xxxx_mult
hdl_library_clause_name = ip_agi027_xxxx_mult_lib
hdl_lib_uses_synth =
hdl_lib_uses_sim =
hdl_lib_technology = #Similar to the mult hdllib of arria10_e1sg, e2sg, e3sge3
synth_files =
ip_agi027_xxxx_mult.vhd
ip_agi027_xxxx_mult_rtl.vhd
test_bench_files =
[modelsim_project_file]
[quartus_project_file]
This diff is collapsed.
-- --------------------------------------------------------------------------
--
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- -------------------------------------------------------------------------
--
-- Author : D.F. Brouwer
-- Purpose:
-- RadioHDL wrapper / Instantiate MULTiplier IP with generics
-- Reference:
-- Copied from */technology/ip_arria10/mult/ip_arria10_mult.vhd and add component declaration lpm_mult from
-- generated/lpm_mult_1920/sim/ip_agi027_xxxx_lpm_mult_lpm_mult_1920_sphm57q.vhd
-- Remark:
-- Directly instantiate LPM component.
-- The Agilex 7 (agi027_xxxx) supports the lpm library, so the copied file can be reused.
-- This is checked by making the IP files on the basis of the generic and port of the entity, and also the generic and port map.
-- The IP file will also remain present in the folder, so that the settings can be reproduced later.
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library lpm;
use lpm.lpm_components.all;
entity ip_agi027_xxxx_mult is
generic (
g_in_a_w : positive := 18; -- Width of the data A port
g_in_b_w : positive := 18; -- Width of the data B port
g_out_p_w : positive := 36; -- Width of the result port
-- g_out_s_w : POSITIVE := 1; -- Width of the sum port (not used in current designs)
g_nof_mult : positive := 1; -- using 2 for 18x18, 4 for 9x9 may yield better results when inferring * is used
g_pipeline_input : natural := 1; -- 0 or 1
g_pipeline_product : natural := 1; -- 0 or 1
g_pipeline_output : natural := 1; -- >= 0
g_representation : string := "SIGNED" -- or "UNSIGNED"
);
port (
clk : in std_logic;
clken : in std_logic := '1';
-- aclr : IN STD_LOGIC := '0'; (not used in current designs)
in_a : in std_logic_vector(g_nof_mult * g_in_a_w - 1 downto 0);
in_b : in std_logic_vector(g_nof_mult * g_in_b_w - 1 downto 0);
-- sum : IN STD_LOGIC_VECTOR(g_nof_mult*g_in_s_w-1 DOWNTO 0) := (OTHERS => '0'); (not used in current designs)
out_p : out std_logic_vector(g_nof_mult * (g_in_a_w + g_in_b_w) - 1 downto 0)
);
end ip_agi027_xxxx_mult;
architecture str of ip_agi027_xxxx_mult is
constant c_pipeline : natural := g_pipeline_input + g_pipeline_product + g_pipeline_output;
-- When g_out_p_w < g_in_a_w+g_in_b_w then the LPM_MULT truncates the LSbits of the product. Therefore
-- define c_prod_w to be able to let common_mult truncate the LSBits of the product.
constant c_prod_w : natural := g_in_a_w + g_in_b_w;
component lpm_mult
generic (
lpm_hint : string;
lpm_pipeline : natural;
lpm_representation : string;
lpm_type : string;
lpm_widtha : natural;
lpm_widthb : natural;
-- lpm_widths : natural;
lpm_widthp : natural
);
port (
dataa : in std_logic_vector(g_nof_mult * g_in_a_w - 1 downto 0);
datab : in std_logic_vector(g_nof_mult * g_in_a_w - 1 downto 0);
-- sum : in STD_LOGIC_VECTOR((g_nof_mult*g_in_s_w-1 DOWNTO 0) := (OTHERS => '0'); (not used in current designs)
-- aclr : in STD_LOGIC; (not used in current designs)
clock : in std_logic;
clken : in std_logic;
result : out std_logic_vector(g_nof_mult * (g_in_a_w + g_in_b_w) - 1 downto 0)
);
end component;
signal prod : std_logic_vector(g_nof_mult * c_prod_w - 1 downto 0);
begin
gen_mult : for I in 0 to g_nof_mult - 1 generate
m : lpm_mult
generic map (
lpm_hint => "MAXIMIZE_SPEED=5", -- default "UNUSED"
lpm_pipeline => c_pipeline,
lpm_representation => g_representation,
lpm_type => "LPM_MULT",
lpm_widtha => g_in_a_w,
lpm_widthb => g_in_b_w,
-- lpm_widths => g_in_s_w, (Partial sum input with not used in current designs)
lpm_widthp => c_prod_w
)
port map (
dataa => in_a((I + 1) * g_in_a_w - 1 downto I * g_in_a_w),
datab => in_b((I + 1) * g_in_b_w - 1 downto I * g_in_b_w),
-- sum => sum((I+1)*g_in_s_w-1 DOWNTO I*g_in_s_w), -- partial sum input is not used in current designs
-- aclr => aclr, -- async clear input is not used in current designs
clock => clk,
clken => clken,
result => prod((I + 1) * c_prod_w - 1 downto I * c_prod_w)
);
out_p <= prod;
---- Truncate MSbits, also for signed (common_pkg.vhd for explanation of RESIZE_SVEC)
-- out_p((I+1)*g_out_p_w-1 DOWNTO I*g_out_p_w) <= RESIZE_SVEC(prod((I+1)*c_prod_w-1 DOWNTO I*c_prod_w), g_out_p_w) WHEN g_representation="SIGNED" ELSE
-- RESIZE_UVEC(prod((I+1)*c_prod_w-1 DOWNTO I*c_prod_w), g_out_p_w);
end generate;
end str;
-- -----------------------------------------------------------------------------
--
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- -----------------------------------------------------------------------------
--
-- Author : D.F. Brouwer
-- Purpose:
-- RadioHDL wrapper
-- Reference:
-- Copied from */technology/ip_arria10/mult/ip_arria10_mult_rtl.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
-- no support for rounding in this RTL architecture
entity ip_agi027_xxxx_mult_rtl is
generic (
g_in_a_w : positive := 18;
g_in_b_w : positive := 18;
g_out_p_w : positive := 36; -- c_prod_w = g_in_a_w+g_in_b_w, use smaller g_out_p_w to truncate MSbits, or larger g_out_p_w to extend MSbits
g_nof_mult : positive := 1; -- using 2 for 18x18, 4 for 9x9 may yield better results when inferring * is used
g_pipeline_input : natural := 1; -- 0 or 1
g_pipeline_product : natural := 1; -- 0 or 1
g_pipeline_output : natural := 1; -- >= 0
g_representation : string := "SIGNED" -- or "UNSIGNED"
);
port (
rst : in std_logic;
clk : in std_logic;
clken : in std_logic := '1';
in_a : in std_logic_vector(g_nof_mult * g_in_a_w - 1 downto 0);
in_b : in std_logic_vector(g_nof_mult * g_in_b_w - 1 downto 0);
out_p : out std_logic_vector(g_nof_mult * (g_in_a_w + g_in_b_w) - 1 downto 0)
);
end ip_agi027_xxxx_mult_rtl;
architecture str of ip_agi027_xxxx_mult_rtl is
constant c_prod_w : natural := g_in_a_w + g_in_b_w;
-- registers
signal reg_a : std_logic_vector(in_a'range);
signal reg_b : std_logic_vector(in_b'range);
signal reg_prod : std_logic_vector(g_nof_mult * c_prod_w - 1 downto 0);
signal reg_result : std_logic_vector(out_p'range);
-- combinatorial
signal nxt_a : std_logic_vector(in_a'range);
signal nxt_b : std_logic_vector(in_b'range);
signal nxt_prod : std_logic_vector(g_nof_mult * c_prod_w - 1 downto 0);
signal nxt_result : std_logic_vector(out_p'range);
-- the active signals
signal inp_a : std_logic_vector(in_a'range);
signal inp_b : std_logic_vector(in_b'range);
signal prod : std_logic_vector(g_nof_mult * c_prod_w - 1 downto 0); -- stage dependent on g_pipeline_product being 0 or 1
signal result : std_logic_vector(out_p'range); -- stage dependent on g_pipeline_output being 0 or 1
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 rst = '1' then
reg_a <= (others => '0');
reg_b <= (others => '0');
reg_prod <= (others => '0');
reg_result <= (others => '0');
elsif rising_edge(clk) then
if clken = '1' then
reg_a <= nxt_a;
reg_b <= nxt_b;
reg_prod <= nxt_prod;
reg_result <= nxt_result;
end if;
end if;
end process;
------------------------------------------------------------------------------
-- Inputs
------------------------------------------------------------------------------
nxt_a <= in_a;
nxt_b <= in_b;
no_input_reg : if g_pipeline_input = 0 generate -- wired
inp_a <= nxt_a;
inp_b <= nxt_b;
end generate;
gen_input_reg : if g_pipeline_input > 0 generate -- register input
inp_a <= reg_a;
inp_b <= reg_b;
end generate;
------------------------------------------------------------------------------
-- Products
------------------------------------------------------------------------------
gen_mult : for I in 0 to g_nof_mult - 1 generate
nxt_prod((I + 1) * c_prod_w - 1 downto I * c_prod_w) <=
std_logic_vector( signed(inp_a((I + 1) * g_in_a_w - 1 downto I * g_in_a_w)) * signed(inp_b((I + 1) * g_in_b_w - 1 downto I * g_in_b_w))) when g_representation = "SIGNED" else
std_logic_vector(unsigned(inp_a((I + 1) * g_in_a_w - 1 downto I * g_in_a_w)) * unsigned(inp_b((I + 1) * g_in_b_w - 1 downto I * g_in_b_w)));
end generate;
no_product_reg : if g_pipeline_product = 0 generate -- wired
prod <= nxt_prod;
end generate;
gen_product_reg : if g_pipeline_product > 0 generate -- register
prod <= reg_prod;
end generate;
------------------------------------------------------------------------------
-- Results
------------------------------------------------------------------------------
nxt_result <= prod;
no_result_reg : if g_pipeline_output = 0 generate -- wired
result <= nxt_result;
end generate;
gen_result_reg : if g_pipeline_output > 0 generate -- register
result <= reg_result;
end generate;
out_p <= result;
end str;
hdl_lib_name = ip_agi027_xxxx_mult_add2
hdl_library_clause_name = ip_agi027_xxxx_mult_add2_lib
hdl_lib_uses_synth = technology common
hdl_lib_uses_sim =
hdl_lib_technology = ip_agi027_xxxx
synth_files =
ip_agi027_xxxx_mult_add2_rtl.vhd
test_bench_files =
[modelsim_project_file]
[quartus_project_file]
-- -----------------------------------------------------------------------------
--
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- -----------------------------------------------------------------------------
--
-- Author : D.F. Brouwer
-- Purpose:
-- RadioHDL wrapper
-- Reference:
-- Copied from */technology/ip_arria10_e2sg/mult_add2/ip_arria10_e2sg_mult_add2.vhd,
-- that is based on ip_stratixiv_mult_add2_rtl
library IEEE, common_lib;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use common_lib.common_pkg.all;
------------------------------------------------------------------------------
-- Function:
-- . res = a0 * b0 + a1 * b1
-- . res = a0 * b0 - a1 * b1
------------------------------------------------------------------------------
entity ip_agi027_xxxx_mult_add2_rtl is
generic (
g_in_a_w : positive;
g_in_b_w : positive;
g_res_w : positive; -- g_in_a_w + g_in_b_w + log2(2)
g_force_dsp : boolean := true; -- when TRUE resize input width to >= 18
g_add_sub : string := "ADD"; -- or "SUB"
g_nof_mult : integer := 2; -- fixed
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_a : in std_logic_vector(g_nof_mult * g_in_a_w - 1 downto 0);
in_b : in std_logic_vector(g_nof_mult * g_in_b_w - 1 downto 0);
res : out std_logic_vector(g_res_w - 1 downto 0)
);
end ip_agi027_xxxx_mult_add2_rtl;
architecture str of ip_agi027_xxxx_mult_add2_rtl is
-- Extra output pipelining is only needed when g_pipeline_output > 1
constant c_pipeline_output : natural := sel_a_b(g_pipeline_output > 0, g_pipeline_output - 1, 0);
constant c_prod_w : natural := g_in_a_w + g_in_b_w;
constant c_sum_w : natural := c_prod_w + 1;
-- registers
signal reg_a0 : signed(g_in_a_w - 1 downto 0);
signal reg_b0 : signed(g_in_b_w - 1 downto 0);
signal reg_a1 : signed(g_in_a_w - 1 downto 0);
signal reg_b1 : signed(g_in_b_w - 1 downto 0);
signal reg_prod0 : signed(c_prod_w - 1 downto 0);
signal reg_prod1 : signed(c_prod_w - 1 downto 0);
signal reg_sum : signed(c_sum_w - 1 downto 0);
signal reg_result : signed(g_res_w - 1 downto 0);
-- combinatorial
signal nxt_a0 : signed(g_in_a_w - 1 downto 0);
signal nxt_b0 : signed(g_in_b_w - 1 downto 0);
signal nxt_a1 : signed(g_in_a_w - 1 downto 0);
signal nxt_b1 : signed(g_in_b_w - 1 downto 0);
signal nxt_prod0 : signed(c_prod_w - 1 downto 0);
signal nxt_prod1 : signed(c_prod_w - 1 downto 0);
signal nxt_sum : signed(c_sum_w - 1 downto 0);
signal nxt_result : signed(g_res_w - 1 downto 0);
-- the active signals
signal a0 : signed(g_in_a_w - 1 downto 0);
signal b0 : signed(g_in_b_w - 1 downto 0);
signal a1 : signed(g_in_a_w - 1 downto 0);
signal b1 : signed(g_in_b_w - 1 downto 0);
signal prod0 : signed(c_prod_w - 1 downto 0);
signal prod1 : signed(c_prod_w - 1 downto 0);
signal sum : signed(c_sum_w - 1 downto 0);
signal result : signed(g_res_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_a0 <= (others => '0');
reg_b0 <= (others => '0');
reg_a1 <= (others => '0');
reg_b1 <= (others => '0');
reg_prod0 <= (others => '0');
reg_prod1 <= (others => '0');
reg_sum <= (others => '0');
reg_result <= (others => '0');
elsif clken = '1' then
reg_a0 <= nxt_a0; -- inputs
reg_b0 <= nxt_b0;
reg_a1 <= nxt_a1;
reg_b1 <= nxt_b1;
reg_prod0 <= nxt_prod0; -- products
reg_prod1 <= nxt_prod1;
reg_sum <= nxt_sum; -- sum
reg_result <= nxt_result; -- result sum after optional rounding
end if;
end if;
end process;
------------------------------------------------------------------------------
-- Inputs
------------------------------------------------------------------------------
nxt_a0 <= signed(in_a( g_in_a_w - 1 downto 0));
nxt_b0 <= signed(in_b( g_in_b_w - 1 downto 0));
nxt_a1 <= signed(in_a(2 * g_in_a_w - 1 downto g_in_a_w));
nxt_b1 <= signed(in_b(2 * g_in_b_w - 1 downto g_in_b_w));
no_input_reg : if g_pipeline_input = 0 generate -- wired
a0 <= nxt_a0;
b0 <= nxt_b0;
a1 <= nxt_a1;
b1 <= nxt_b1;
end generate;
gen_input_reg : if g_pipeline_input > 0 generate -- register input
a0 <= reg_a0;
b0 <= reg_b0;
a1 <= reg_a1;
b1 <= reg_b1;
end generate;
------------------------------------------------------------------------------
-- Products
------------------------------------------------------------------------------
nxt_prod0 <= a0 * b0;
nxt_prod1 <= a1 * b1;
no_product_reg : if g_pipeline_product = 0 generate -- wired
prod0 <= nxt_prod0;
prod1 <= nxt_prod1;
end generate;
gen_product_reg : if g_pipeline_product > 0 generate -- register
prod0 <= reg_prod0;
prod1 <= reg_prod1;
end generate;
------------------------------------------------------------------------------
-- Sum
------------------------------------------------------------------------------
gen_add : if g_add_sub = "ADD" generate
nxt_sum <= RESIZE_NUM(prod0, c_sum_w) + prod1;
end generate;
gen_sub : if g_add_sub = "SUB" generate
nxt_sum <= RESIZE_NUM(prod0, c_sum_w) - prod1;
end generate;
no_adder_reg : if g_pipeline_adder = 0 generate -- wired
sum <= nxt_sum;
end generate;
gen_adder_reg : if g_pipeline_adder > 0 generate -- register
sum <= reg_sum;
end generate;
------------------------------------------------------------------------------
-- Result sum after optional rounding
------------------------------------------------------------------------------
nxt_result <= RESIZE_NUM(sum, g_res_w);
no_result_reg : if g_pipeline_output = 0 generate -- wired
result <= nxt_result;
end generate;
gen_result_reg : if g_pipeline_output > 0 generate -- register
result <= reg_result;
end generate;
res <= std_logic_vector(result);
end str;
# ------------------------------------------------------------------------------
#
# Copyright (C) 2023
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ------------------------------------------------------------------------------
# Author: D.F. Brouwer
# Description:
# This file is based on generated file mentor/msim_setup.tcl.
# - the values for modelsim_search_libraries key in the hdllib.cfg follow from altera libraries vmap section in the msim_setup.tcl
# - vmap for the IP specific libraries and compile all IP source files into those libraries similar as in the msim_setup.tcl
# - replace QSYS_SIMDIR by IP_DIR
# - if the testbench is also generated with QSYS then only the IP_TBDIR files are needed, because these also contain the source files.
#vlib ./work/ ;# Assume library work already exist
set IP_DIR "$env(HDL_BUILD_DIR)/$env(BUILDSET)/qsys-generate/ip_agi027_xxxx_mult_add4/sim"
vmap ip_agi027_xxxx_mult_add4 ./work/
vmap altera_mult_add_1920 ./work/
vcom "$IP_DIR/../altera_mult_add_1920/sim/ip_agi027_xxxx_mult_add4_altera_mult_add_1920_ljq3huq.vhd" -work altera_mult_add_1920
vcom "$IP_DIR/ip_agi027_xxxx_mult_add4.vhd" -work ip_agi027_xxxx_mult_add4
hdl_lib_name = ip_agi027_xxxx_mult_add4
hdl_library_clause_name = ip_agi027_xxxx_mult_add4_lib
hdl_lib_uses_synth = technology common
hdl_lib_uses_sim =
hdl_lib_technology = ip_agi027_xxxx
synth_files =
ip_agi027_xxxx_mult_add4_rtl.vhd
test_bench_files =
[modelsim_project_file]
[quartus_project_file]
[generate_ip_libs]
qsys-generate_ip_files =
ip_agi027_xxxx_mult_add4.ip
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment