AR# 4949: FPGA Express: Implementing efficient multipliers in VHDL or Verilog
AR# 4949
|
FPGA Express: Implementing efficient multipliers in VHDL or Verilog
説明
Keywords: Express, mult, multiply, VHDL, Verilog, Foundation Express
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.
ソリューション
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));
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;