Table of Contents

Example of a Multiplier

Introduction

Multiplier Block Diagram

entity MULTIPLIER is 
 port (A0  : in  bit;
       A1  : in  bit;
       B0  : in  bit;
       B1  : in  bit;
       C0  : out bit;
       C1  : out bit;
       C2  : out bit;
       C3  : out bit);
end MULTIPLIER;

Notes

Different VHDL coding styles shall be demonstrated with a simple module that has to calculate the result of the multiplication of two 2-bit numbers. The maximum value of each input is 3, i.e. the maximum output value is 9 which needs 4 bits in a binary code.

Therefore, four input ports and four output ports of data type ’bit’ are required.

The same entity shall be used for all different implementations.

Mutliplier: Function Table

a1 a0 b1 b0 c3 c2 c1 c0
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 1 0 0 0 0
0 1 0 0 0 0 0 0
0 1 0 1 0 0 0 1
0 1 1 0 0 0 1 0
0 1 1 1 0 0 1 1
1 0 0 0 0 0 0 0
1 0 0 1 0 0 1 0
1 0 1 0 0 1 0 0
1 0 1 1 0 1 1 0
1 1 0 0 0 0 0 0
1 1 0 1 0 0 1 1
1 1 1 0 0 1 1 0
1 1 1 1 1 0 0 1

Notes

The most direct approach is via the function table of the multiplications. The behavior of a combinational logic block is completely defined by listing the result for all possible input values. Of course, the function table is usually no the most compact representation.

Multiplier Minterms - Karnaugh Diagram

Karnaugh Diagram

Multiplier Miniterms

Notes

The function table of this 2×2 bit multiplier leads directly to the four Karnaugh diagrams of the output signals.

The bars on the side of the squares indicate those regions where the corresponding input bit is ’1’.

All ’1’s of the output signals are marked in the corresponding diagrams. By combining adjacent ’1’s, the minimal output function can be derived.

Multiplier: VHDL Code using the Function Tables

architecture RTL_TABLE of MULTIPLIER is 
  signal A_B : bit_vector ( 3 downto 0);
begin
  A_B <= A1 & A0 & B1 & B0;
  MULTIPLY : process (A_B)
  begin
   case A_B is 
    when “0000” => (C3,C2,C1,C0) <= “0000”;
    when “0001” => (C3,C2,C1,C0) <= “0000”;
    when “0010” => (C3,C2,C1,C0) <= “0000”;
    when “0011” => (C3,C2,C1,C0) <= “0000”;
    when “0100” => (C3,C2,C1,C0) <= “0000”;
    when “0101” => (C3,C2,C1,C0) <= “0001”;
    when “0110” => (C3,C2,C1,C0) <= “0010”;
    when “0111” => (C3,C2,C1,C0) <= “0011”;
   ...
    when1100=> (C3,C2,C1,C0) <= “0000”;
    when1101=> (C3,C2,C1,C0) <= “0011”;
    when1110=> (C3,C2,C1,C0) <= “0110”;
    when1111=> (C3,C2,C1,C0) <=1001;
  end case;
 end process MULTIPLY;
end RTL_TABLE;

Notes

The conversion of the function table into VHDL is straight forward. An intermediate signal is used to combine the four input signals which facilitates the coding. Every row is represented by a different signal value, now. As all possibilities are covered in the table, a case structure can be used for the implementation.

Multiplier: VHDL Code using Minterm Functions

architecture RTL_MINTERM of MULTIPLIER is
begin
 
  C0 <= A0 and B0;
 
  C1 <= (A0 and not A1 and B1) or 
        (A0 and not B0 and B1) or
        (not A0 and A1 and B0) or
        (A0 and B0 and not B1);
 
  C2 <= (A1 and B1 and not B0) or 
        (A1 and not A0 and B1);
 
  C3 <= A1 and A0 and B1 and B0;
 
end  RTL_MINTERM;

Notes

Because the minterms are rather simple logical functions, they are realized with concurrent statements. This way, it is just a matter of replacing the mathematical symbols with their corresponding VHDL operators.

The minterm realization is very tedious and is performed by the synthesis tool automatically when the function table is parsed.

It is more or less a structural implementation of the algorithm - no synthesis is required.

Multiplier: Integer Realization

library IEEE;
use IEEE.NUMERIC_BIT.all;
 
architecture RTL_INTEGER
of MULTIPLIER is 
  signal A_VEC : unsigned (1 downto 0 );
  signal B_VEC : unsigned (1 downto 0 );  
  signal A_INT : integer range 0 to 3;
  signal B_INT : integer range 0 to 3;
  signal C_VEC : unsigned (3 downto 0 );
  signal C_INT : integer range 0 to 9;
begin
 
  A_VEC <= A1 & A0;
  A_INT <= TO_INTEGER(A_VEC);
  B_VEC <= B1 & B0;
  B_INT <= TO_INTEGER(B_VEC);
 
  C_INT <= A_INT * B_INT;
 
  C_VEC <= TO_UNSIGNED(C_INT, 4);
 
  (C3, C2, C1, C0) <= C_VEC;
end RTL_INTEGER;

Notes

The most obvious solution via the multiplication operator ’*’ is not directly applicable because only single bits are provided by the entity.

Thus, bits belonging together are combined in bit vectors which are converted to integer values afterwards. The inverse procedure is necessary to assign the integer result to the output ports.

The most elegant solution is the integer implementation as the function of the code is clearly visible and not hidden in boolean functions or in hardcoded values like in the other examples. The use of ’bit’ type ports, however, is very awkward.

It is better style to use ’unsigned’ bit vectors or ’integer’. Please note that the conversion of the bit vectors to ’integer’ is not necessary as the arithmetic operators, including ’*’ are overloaded in the NUMERIC_BIT package. Vector arithmetic is provided for signed and unsigned binary representations

The synthesis result should be identical in all three cases.