Skip to content
Snippets Groups Projects
Commit 5ac57396 authored by Zanting's avatar Zanting
Browse files

Added Arria 10 complex multiplier (IP and RTL version)

parent 78ab0261
No related branches found
No related tags found
No related merge requests found
README.txt for $RADIOHDL/libraries/technology/ip_arria10/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 v11.1 for Stratix IV to Quartus 15.0 for Arria10 by creating it in Qsys using
the same parameter settings.
2) IP component
The generated IP is not kept in SVN, only the Qsys source file:
ip_arria10_complex_mult.qsys
Therefore first the IP needs to be generated using:
./generate_ip.sh
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:
generated/ip_arria10_complex_mult.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
The generated ip_arria10_<lib_name>.vhd uses an IP specific library name. Therefore the hdllib.cfg uses the IP
specific library as library clause name to make it known:
hdl_lib_name = ip_arria10_<lib_name>
hdl_library_clause_name = ip_arria10_<lib_name>_<ip_specific>
\ No newline at end of file
#------------------------------------------------------------------------------
#
# Copyright (C) 2015
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# JIVE (Joint Institute for VLBI in Europe) <http://www.jive.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/>.
#
#------------------------------------------------------------------------------
# This file is based on generated file generated/sim/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
set IP_DIR "$env(RADIOHDL)/libraries/technology/ip_arria10/complex_mult/generated/sim"
#vlib ./work/ ;# Assume library work already exists
vmap ip_arria10_complex_mult_altmult_complex_150 ./work/
vlog "$IP_DIR/../altmult_complex_150/sim/ip_arria10_complex_mult_altmult_complex_150_35pzchy.v" -work ip_arria10_complex_mult_altmult_complex_150
vcom "$IP_DIR/ip_arria10_complex_mult.vhd"
#!/bin/bash
# -------------------------------------------------------------------------- #
#
# Copyright (C) 2014
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# JIVE (Joint Institute for VLBI in Europe) <http://www.jive.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/>.
#
# -------------------------------------------------------------------------- #
#
# Purpose: Generate IP with Qsys
# Description:
# Generate the IP in a separate generated/ subdirectory.
#
# Usage:
#
# ./generate_ip.sh
#
# Tool settings for selected target "unb2" with arria10
. ${RADIOHDL}/tools/quartus/set_quartus unb2
#qsys-generate --help
# Only generate the source IP
# - use --synthesis=VHDL to have top level in VHDL similar as with MegaWizard
qsys-generate ip_arria10_complex_mult.qsys \
--synthesis=VHDL \
--simulation=VHDL \
--output-directory=generated \
--allow-mixed-language-simulation
hdl_lib_name = ip_arria10_complex_mult
hdl_library_clause_name = ip_arria10_complex_mult_altmult_complex_150
hdl_lib_uses_synth =
hdl_lib_uses_sim =
hdl_lib_technology = ip_arria10
modelsim_compile_ip_files =
$RADIOHDL/libraries/technology/ip_arria10/complex_mult/compile_ip.tcl
synth_files =
test_bench_files =
quartus_qip_files =
generated/ip_arria10_complex_mult.qip
<?xml version="1.0" encoding="UTF-8"?>
<system name="$${FILENAME}">
<component
name="$${FILENAME}"
displayName="$${FILENAME}"
version="1.0"
description=""
tags="INTERNAL_COMPONENT=true"
categories="" />
<parameter name="bonusData"><![CDATA[bonusData
{
element $${FILENAME}
{
}
element altmult_complex_0
{
datum _sortIndex
{
value = "0";
type = "int";
}
}
}
]]></parameter>
<parameter name="clockCrossingAdapter" value="HANDSHAKE" />
<parameter name="device" value="10AS066H2F34E1SG" />
<parameter name="deviceFamily" value="Arria 10" />
<parameter name="deviceSpeedGrade" value="1" />
<parameter name="fabricMode" value="QSYS" />
<parameter name="generateLegacySim" value="false" />
<parameter name="generationId" value="0" />
<parameter name="globalResetBus" value="false" />
<parameter name="hdlLanguage" value="VERILOG" />
<parameter name="hideFromIPCatalog" value="true" />
<parameter name="lockedInterfaceDefinition" value="" />
<parameter name="maxAdditionalLatency" value="1" />
<parameter name="projectName" value="" />
<parameter name="sopcBorderPoints" value="false" />
<parameter name="systemHash" value="0" />
<parameter name="testBenchDutName" value="" />
<parameter name="timeStamp" value="0" />
<parameter name="useTestBenchNamingPattern" value="false" />
<instanceScript></instanceScript>
<interface
name="complex_input"
internal="altmult_complex_0.complex_input"
type="conduit"
dir="end">
<port name="dataa_real" internal="dataa_real" />
<port name="dataa_imag" internal="dataa_imag" />
<port name="datab_real" internal="datab_real" />
<port name="datab_imag" internal="datab_imag" />
<port name="clock" internal="clock" />
<port name="aclr" internal="aclr" />
<port name="ena" internal="ena" />
</interface>
<interface
name="complex_output"
internal="altmult_complex_0.complex_output"
type="conduit"
dir="end">
<port name="result_real" internal="result_real" />
<port name="result_imag" internal="result_imag" />
</interface>
<module
name="altmult_complex_0"
kind="altmult_complex"
version="15.0"
enabled="1"
autoexport="1">
<parameter name="CBX_AUTO_BLACKBOX" value="ALL" />
<parameter name="DEVICE_FAMILY" value="Arria 10" />
<parameter name="GUI_DYNAMIC_COMPLEX" value="false" />
<parameter name="GUI_USE_ACLR" value="true" />
<parameter name="GUI_USE_CLKEN" value="true" />
<parameter name="IMPLEMENTATION_STYLE" value="AUTO" />
<parameter name="PIPELINE" value="3" />
<parameter name="REPRESENTATION_A" value="1" />
<parameter name="REPRESENTATION_B" value="1" />
<parameter name="WIDTH_A" value="18" />
<parameter name="WIDTH_B" value="18" />
<parameter name="WIDTH_RESULT" value="36" />
</module>
<interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" />
<interconnectRequirement for="$system" name="qsys_mm.enableEccProtection" value="FALSE" />
<interconnectRequirement for="$system" name="qsys_mm.insertDefaultSlave" value="FALSE" />
<interconnectRequirement for="$system" name="qsys_mm.maxAdditionalLatency" value="1" />
</system>
hdl_lib_name = ip_arria10_complex_mult_rtl
hdl_library_clause_name = ip_arria10_complex_mult_rtl_lib
hdl_lib_uses_synth =
hdl_lib_uses_sim =
hdl_lib_technology = ip_arria10
synth_files =
ip_arria10_complex_mult_rtl.vhd
test_bench_files =
-------------------------------------------------------------------------------
--
-- Copyright (C) 2009
-- 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/>.
--
-------------------------------------------------------------------------------
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_arria10_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_arria10_complex_mult_rtl;
ARCHITECTURE str OF ip_arria10_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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment