Here we look at the design of a multiplier used in the receive path of a mobile digital communications system. The key feature of this multiplier is that the operands are of remarkably different wordlengths.
The multiplier is used in the synchronizer section of a system to maintain tracking between base stations. One aspect of the requirements for such a system is that the coefficients are often in the range -1 to +1, though a generous guard band is required to cater for extraordinary conditions (range -7 to +7). The data is required to maintain accuracy over many accumulations and under extraordinary conditions may grow to 22 bits. Thus a 22-bit by 4-bit signed multiplier design is required.
The multiplier is designed as a scaler rather than a typical multiplier. This is only feasible due to the short coefficient wordlength. In fact, designing a multiplier for a 5-bit coefficient yields better results when twin scalers feeding a common accumulator are used rather than a single scaler.
In order to ensure as fast a design as possible, the 4-bit signed coefficient input is recoded, as follows:
Coefficient |
Recoding |
7 |
8-1 |
6 |
8-2 |
5 |
4+1 |
4 |
4+0 |
3 |
4-1 |
2 |
4-2 |
1 |
0+1 |
0 |
0+0 |
-1 |
-(0+1) |
-2 |
-(0+2) |
-3 |
-(4-1) |
-4 |
-(4-0) |
-5 |
-(4+1) |
-6 |
-(4+2) |
-7 |
-(8-1) |
-8 |
-(8-0) |
Obviously there is more than one recode value for some coefficient values (6 can be 8-2 or 4+2), so the recode values were chosen to maximize the symmetry in both the operator (+, -) and the recode operands. Maximizing symmetry minimizes the amount of hardware required for the recoding.
The advantage of recoding is that the multiplier design can now be realised as a pair of binary scalers (multiplexer-based shifters) feeding an adder-subtractor. Further investigation of the recoding shows that each binary scaler requires only 3 input values (corresponding to 0, 4, 8). The negative values (-1 to -8) require an extra negation, but fortunately in the context of the system, the accumulator following the scaler can be implemented as an adder-subtractor feeding the accumulating register. The scaler itself is thus VHDL-coded as a signed datapath scaler minus the negation stage, but with an output negate flag to control the following add-subtract accumulator.
There are no VHDL subtleties in this model, just pure hardware design techniques!
You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details).
-- +-----------------------------+ -- | Copyright 1996-2008 DOULOS | -- | Library: arithmetic | -- | designer : Tim Pagden | -- | opened: 30 Jul 1996 | -- +-----------------------------+ -- Architectures: -- 30.07.96 low_level library arithmetic; library multiplexer; architecture low_level of scaler_4s_22s_negate_out is use multiplexer.mux_3_25_cmpt.all; use arithmetic.adder_25_cmpt.all; signal a_shift_3 : std_logic_vector(24 downto 0); signal a_shift_2 : std_logic_vector(24 downto 0); signal a_shift_1 : std_logic_vector(24 downto 0); signal a_pass : std_logic_vector(24 downto 0); signal lo_25 : std_logic_vector(24 downto 0); signal sel_left : std_logic_vector(1 downto 0); signal sel_right : std_logic_vector(1 downto 0); signal left_shift_in : std_logic_vector(74 downto 0); signal right_shift_in : std_logic_vector(74 downto 0); signal left_shift_out : std_logic_vector(24 downto 0); signal right_shift_out : std_logic_vector(24 downto 0); signal right_shift_xor : std_logic_vector(24 downto 0); signal subtract : std_logic; begin sel_left_0: sel_left(0) <= b(2) xor b(1); sel_left_1: process (b(3 downto 1)) begin if b(3) = '0' then sel_left(1) <= b(2) and b(1); else sel_left(1) <= b(2) nor b(1); end if; end process; sel_right_0: sel_right(0) <= b(0); sel_right_1: sel_right(1) <= (not b(0)) and b(1); a3: a_shift_3 <= a & "000"; a2: a_shift_2 <= a(21) & a & "00"; a1: a_shift_1 <= a(21) & a(21) & a & '0'; ap: a_pass <= a(21) & a(21) & a(21) & a; lo: lo_25 <= (others => '0'); left_shift_in <= a_shift_3 & a_shift_2 & lo_25; right_shift_in <= a_shift_1 & a_pass & lo_25; subtract <= b(3) xor b(1); negate <= b(3); process (subtract, right_shift_out) begin if subtract = '0' then right_shift_xor <= right_shift_out; else right_shift_xor <= not right_shift_out; end if; end process; left_shifter: mux_3_25 port map ( a => left_shift_in, sel => sel_left, y => left_shift_out ); right_shifter: mux_3_25 port map ( a => right_shift_in, sel => sel_right, y => right_shift_out ); i0_0: adder_25 port map ( c_in => subtract, a => left_shift_out, b => right_shift_xor, y => y, c_out => open ); end low_level;
To download the VHDL source code for this model, click here.