Answers Database


FPGA Express: Implementing efficient multipliers in VHDL or Verilog


Record #4949

Product Family: Software

Product Line: Synopsys

Product Part: FPGA Express

Product Version: 2.1.3

Problem Title:
FPGA Express: Implementing efficient multipliers in VHDL or Verilog


Problem Description:
Urgency: Hot

General Description:
FPGA Express uses specific Xilinx features for arithmetic functions when
implementing designs. However, multiplier implementations are not optimal for
performance (Virtex excepted). These results have been greatly improved
with v3.2 of FPGA Express, so this solution should be applied when using
Express v3.1 and earlier.

Use the following VHDL package containing a multiplier function to implement
much more efficient multipliers for XC4000 and Spartan architectures.


Solution 1:

Copy the VHDL code listed in Solution 2 to a VHDL file called mult_package.vhd. Analyze this package file in your Express project first, before your design
files. Or, create a new library and add this package file to that library.

Then, refer to this package in the library declaration portion of your VHDL
code. The name of the package is "my_arith" and the library will be "work"
unless you have created your own. Then, call the "my_mult" function within
VHDL code using the following code. Copy the following code to a file called
multiply.vhd and add this to your Express project.


--save this file as multiply.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
use work.my_arith.all;	    -- refers to the package listed in Solution 2

entity multiply is
  port(a : in std_logic_vector(20 downto 0);	    --<- Change these bounds
       b : in std_logic_vector(13 downto 0);	    --<- to change the size
       prod : out std_logic_vector(34 downto 0));   --<- of the multiplier
end multiply;

architecture nice of multiply is
begin
      prod <= my_mult(a, b);	   -- multiply "a" and "b" to produce "prod"
end nice;



For VHDL designs, the my_mult function can be used in any file as shown above.

For Verilog designs, instantiate "multiply" to call the function as follows:


   multiply U1 (.a(x), .b(y), .prod(z));



NOTE: In a sequential block (VHDL `process' or Verilog `always'), perform an
assignment from a temporary signal, then instantiate the multiplier outside
the sequential block in such a way that the temporary signal is the output of
the multiplier instantiation.

Example:

always@(posedge clk)
   QOUT <= TEMP;

multiply U1 (.a(X), .b(Y), .prod(TEMP));




Solution 2:

-- save this file as mult_package.vhd
----------------------------------------------------------------------------
--
-- Copyright (c) 1998 by Synopsys, Inc.  All rights reserved.
--
-- This source file may be used and distributed without restriction
-- provided that this copyright statement is not removed from the file
-- and that any derivative work contains this copyright notice.
--
--	Package name: my_arith
--
--	Purpose: This package defines a more efficient implementation
--		 for the multiplication operator
--
-- Author: Ramine Roane (rroane@synopsys.com)
--
--     Algorithm:
--	       loop: Pi = (Yi==1) ? Xi : 0
--	       loop: Qi = P(2i) + P(2i+1)<<1
--	       loop: Ri = Q(2i) + Q(2i+1)<<2
--	       If T'length > 7
--		  loop: Ti = R(2i) + R(2i+1)<<4
--		  loop: Q += Ti<<(8i)
--	       else
--		  loop: Q += Ri<<(4i)
--	       end if
--
--     Notes: Partial products Qi's ccomputed in parallel
--	      Partial products Ri's ccomputed in parallel
-- Partial products Ti's (if apply) ccomputed in parallel
--
--
----------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

package my_arith is
   function my_mult(S, L: std_logic_vector) return std_logic_vector;
end my_arith;

package body my_arith is

function largest(X, Y: INTEGER) return INTEGER is
begin
    if X > Y then return X;
    else return Y;
    end if;
end;

function smallest(X, Y: INTEGER) return INTEGER is
begin
    if X < Y then return X;
    else return Y;
    end if;
end;

function my_mult(S, L: std_logic_vector) return std_logic_vector is
    constant lS : integer := smallest(S'length, L'length);
    constant lL : integer := largest(S'length, L'length);

-- Number of intermediate products P, Q, R
    constant nP : integer := lS;
    constant nQ : integer := (nP+1)/2;
    constant nR : integer := (nQ+1)/2;
    constant nT : integer := (nR+1)/2;

-- Length of P, Q, R, and final result
    constant lP : integer := Ll;
    constant lQ : integer := lP+2;
    constant lR : integer := lQ+3;
    constant lT : integer := lR+5;
    constant n : integer := lS+lP;

    type Pi_type is array(nP-1 downto 0) of std_logic_vector(lP-1 downto 0);
    type Qi_type is array(nQ-1 downto 0) of std_logic_vector(lQ-1 downto 0);
    type Ri_type is array(nR-1 downto 0) of std_logic_vector(lR-1 downto 0);
    type Ti_type is array(nT-1 downto 0) of std_logic_vector(lT-1 downto 0);

    variable P : Pi_type;
    variable Q : Qi_type;
    variable R : Ri_type;
    variable T : Ti_type;
    variable result: std_logic_vector(n-1 downto 0);
    variable Small : std_logic_vector(ls-1 downto 0);
    variable Large : std_logic_vector(Ll-1 downto 0);

begin

    if (S'length < L'length) then
       Small := S;
       Large := L;
    else
       Small := L;
       Large := S;
    end if;

-- Compute Pi's
    for i in 0 to nP-1 loop
       if (Small(i) = '0') then P(i) := (others => '0');
       else P(i) := Large;
       end if;
    end loop;

-- Compute Qi's
    for i in 0 to nP/2-1 loop
      Q(i) := (EXT(P(2*i)(lP-1 downto 1),lQ-1) + EXT(P(2*i+1),lQ-1)) & P(2*i)(0);
    end loop;
    if (nP mod 2) = 1 then
      Q(nQ-1) := EXT(P(nP-1), lQ);
    end if;

-- Compute Ri's
    for i in 0 to nQ/2-1 loop
      R(i):=(EXT(Q(2*i)(lQ-1 downto 2),lR-2) + EXT(Q(2*i+1),lR-2)) & Q(2*i)
(1 downto 0);
    end loop;
    if (nQ mod 2) = 1 then
      R(nR-1) := EXT(Q(nQ-1), lR);
    end if;

    if (lS >= 8) then
    -- Compute Ti's
       for i in 0 to nR/2-1 loop
      T(i) := (EXT(R(2*i)(lR-1 downto 4),lT-4) + EXT(R(2*i+1),lT-4)) &
R(2*i)(3 downto 0);
       end loop;
       if (nR mod 2) = 1 then
      T(nT-1) := EXT(R(nR-1), lT);
       end if;

    -- Compute final product
       result := EXT(T(0), n);
       for i in 1 to nT-1 loop -- skip i=0
      result := result + (EXT(T(i) & EXT("0", 8*i), n));
       end loop;
    else

    -- Compute final product
       result := EXT(R(0), n);
       for i in 1 to nR-1 loop -- skip i=0
      result := result + (EXT(R(i) & EXT("0", 4*i), n));
       end loop;
    end if;

    return result;
end;

end my_arith;





End of Record #4949 - Last Modified: 05/10/99 15:39

For the latest news, design tips, and patch information on the Xilinx design environment, check out the Technical Tips!