##
**Parameterizable Multiplier using Ripple carry adder**

**1.1**

**Aim**

The aim of this project is to implement a parameterizable multiplier using for/generate statement to describe repeating components/assignments. The size of the multiplier should be adjustable using parameter data width (possible values are 2, 3, 4, … , 8) that would enable multiplication of binary digits. Below is the list of steps to follow in implementing this task:

· Describe a parameterizable ripple-carry adder. It should be possible to adjust its size using parameter data width (possible values are 2, 3, 4, ... , 8).

· Use parameterizable adder as a component to describe a parameterizable multiplier that implements multiplication using columnar addition. It should be possible to adjust its size using parameter data width (possible values are 2, 3, 4, ... , 8).

1.2

**Background**
Here it’s needed to use the for/generate statement in other to eradicate the possibility of reusing code repeatedly within an architecture

**1.3**

**Workflow**

###
**Implementation of Ripple carry adder**

**Implementation of Ripple carry adder**

According to the first task in this laboratory, a parameterizable 4-bit ripple-carry adder is designed by instantiating a full adder four times. Fugure 1:

I have started the implementation by declaring the port and also assigned generic "datawidth" right above the Port within the entity :

**Listing 1**

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity ripple_adder is

generic (datawidth: in integer);

Port ( a : in STD_LOGIC_vector(datawidth-1 downto 0);

b : in STD_LOGIC_vector(datawidth-1 downto 0);

cin : in STD_LOGIC;

cout : out STD_LOGIC;

sum : out STD_LOGIC_vector(datawidth-1 downto 0));

end ripple_adder;

architecture Behavioral of ripple_adder is

component full_adder is

port (

a, b : in STD_LOGIC;

cin1 : in std_logic;

sum1, cout1 : out std_logic);

end component;

signal carry: std_logic_vector(a'length-1 downto 0);

begin

gen: for g in b'range generate

genlsb: if g = 0 generate

fa_lsb: full_adder port map ( a=>a(0), b =>b(0), cin1 =>cin, sum1=>sum(0), cout1 => carry(1));

end generate;

genmid: if (g>0) and (g< a'length-1) generate

fa_mid: full_adder port map(a => a(g), b => b(g), cin1 => carry(g), sum1 =>sum(g), cout1=> carry(g+1));

end generate;

genmsb : if g = a'length-1 generate

fa_msb: full_adder port map(a=>a(g), b=>b(g), cin1=>carry(g), sum1 =>sum(g), cout1=>cout);

end generate;

end generate;

end Behavioral;

As it shown from Figure 1 a ripple carry adder is considered an adder with its carry ripple via every bit from the right to the left. Cin represents the carry in bit and cout represent the carry out bit and S represent the sum outputs whereas A and B are inputs. In this implementation, generate statements are used for instantiating the full adder components. I have also used generic to defined the data width needed as an integer value within the entity.

I have also considered (encapsulation of full adder as component within the architecture of the ripple carry adder) the usefulness of full adder that adds 3 bits, namely a , b and cin and produce two outputs of sum and cout.

I used “b’range” to access the range from b’left downto b’right. Since both a and b have the same range therefore using b’range to access the range of b is the same as accessing the range of a.

*for g in b’range generate*

The meaning of this statement is to use g to iterate through the possible range of b whereby using of if statement to set the initial value for each necessary port is possible and further allows the port mapping with those values set.

E.g. I have generated the least significant by further declaration of if statement and right under the statement I applied the values within the full adder port mapping:

genlsb: if g = 0 generate

fa_lsb: full_adder port map ( a=>a(0), b =>b(0), cin =>cin, sum=>sum(0), cout => carry(1));

end generate;

Moreover there are two assignment to take note the cin and the cout, these two are different from other assignments in that line because of the way they carry their bits even if a and b are set to 0, cin carries bit in and cout carries bit out and serves as input of another full adder figure 1.1 below shows:

####
__Ripple carry adder Testbench__

I have practically used the same method for generating the waveform for both multiplier and the ripple carry adder, I will explain more about this logic under the multiplier testbench, below shows the part of the code for the Ripple carry adder testbench and figure 1.2 shows the simulation waveform of the ripple carry adder:

**Listing 2:**

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

entity ripple_adder_tb is

-- Port ( );

end ripple_adder_tb;

architecture Behavioral_rapper of ripple_adder_tb is

component ripple_adder is

generic (datawidth:integer :=4);

Port ( a : in STD_LOGIC_vector(datawidth-1 downto 0);

b : in STD_LOGIC_vector(datawidth-1 downto 0);

cin : in STD_LOGIC;

cout : out STD_LOGIC;

sum : out STD_LOGIC_vector(datawidth-1 downto 0));

end component;

constant datawidth : integer := 4;

signal a_tb, b_tb : std_logic_vector(datawidth-1 downto 0);

signal cin_tb: std_logic_vector(datawidth-datawidth downto 0);

signal cout_tb : std_logic;

signal sum_tb : std_logic_vector(datawidth-1 downto 0);

signal sum_and_carry : STD_LOGIC_VECTOR (datawidth downto 0);

begin

riple_adder: ripple_adder

generic map (datawidth=>datawidth)

port map (a=>a_tb,b=>b_tb,cin=>cin_tb(0),sum=>sum_tb, cout=>cout_tb );

sum_and_carry(datawidth-1 downto 0)<=sum_tb;

sum_and_carry(datawidth) <= cout_tb;

process

constant period: time := 10ns;

begin

for c in 0 to 1 loop

cin_tb<=std_logic_vector(to_unsigned(c,1));

for i in 0 to 2**datawidth-1 loop

a_tb <= std_logic_vector(to_unsigned(i,datawidth));

for j in 0 to 2**datawidth-1 loop

b_tb<= std_logic_vector(to_unsigned(j,datawidth));

wait for period;

assert(sum_and_carry = std_logic_vector(to_unsigned(i,datawidth + 1) + to_unsigned(j,datawidth + 1) + to_unsigned(c ,1)))

report "test failed for specified input combination"

severity error ;

end loop;

end loop;

end loop;

wait;

end process;

end Behavioral_rapper;

Figure 1.2 Waveform for ripple carry adder

###
** ** 1.4 **Implementation of Parameterizable Multiplier**

Here, I have implemented a parameterizable multiplier that permits multiplication using columnar addition. It is possible to adjust its size using parameter data width (possible values are 2, 3, 4, ... , 8).

Figure 1.4 below shows the multiplication process on how this multiplier should work

Figure 1.4 Example of Multiplication Using Columnar Addition.

I have started the implementation by declaring the port and also assigned generic datawidth right above the Port within the entity :

**Listing 3**

*library IEEE;*

*use IEEE.STD_LOGIC_1164.ALL;*

*entity Multiplier is*

*generic (datawidth_m: integer:= 4);*

*Port ( aa : in STD_LOGIC_vector(datawidth_m-1 downto 0);*

*bb : in STD_LOGIC_vector(datawidth_m-1 downto 0);*

*product : OUT STD_LOGIC_vector((2*datawidth_m)-1 downto 0));*

*end Multiplier;*

*architecture Behavioral of Multiplier is*

*component ripple_adder is*

*generic (datawidth: integer:= datawidth_m);*

*Port ( a : in STD_LOGIC_vector(datawidth-1 downto 0);*

*b : in STD_LOGIC_vector(datawidth-1 downto 0);*

*cin : in STD_LOGIC;*

*cout : out STD_LOGIC;*

*sum : out STD_LOGIC_vector(datawidth-1 downto 0));*

*end component;*

*type r_adder is array (0 to datawidth_m-1) of std_logic_vector(datawidth_m-1 downto 0);*

*signal Partial_Product, Partial_Sum, b_signal : r_adder;*

*type carry is array (0 to datawidth_m-1) of std_logic;*

*signal Partial_Carry : carry;*

*begin*

*--getting the partial products*

*getting_Partial_Sums:for i in 0 to datawidth_m-1 generate*

*inner_PP: for m in 0 to datawidth_m-1 generate*

*Partial_Sum(i)(m)<= aa(i) and bb(m);*

*end generate;*

*end generate;*

*Partial_Product(0)<=Partial_Sum(0);*

*Partial_Carry(0)<='0';*

*using_the_ripple_adder: for f in 1 to datawidth_m-1 generate*

*b_signal(f)<= Partial_Carry(f-1)&Partial_Product(f-1)(datawidth_m-1 downto 1);*

*dut: component ripple_adder*

*port map*

*(*

*cin=>'0', --RN*

*cout=>Partial_Carry(f), -- RN*

*a=>Partial_sum(f), --RN*

*b=> b_signal(f),*

*sum=>Partial_Product(f) --RN*

*);*

*end generate;*

*product( (2*datawidth_m)-1 downto datawidth_m-1 )<= Partial_Carry(datawidth_m-1)&Partial_Product(datawidth_m-1);*

*get_the_rest:for t in 0 to datawidth_m-2 generate*

*product(t) <= Partial_Product(t)(0);*

*end generate;*

*end Behavioral;*

I have used constrained vector arrays in the for/generate description of the multiplier because of the inputs and outputs of the ripple-carry adders.

**type r_adder is array (0 to datawidth_m-1) of std_logic_vector(datawidth_m-1 downto 0);**

###
**1.5 ****Multiplier Testbench**

The testbench stimulus process help to show the logical behavior of the multiplier code in a simulated form with the help of assert statement. The testbench encapsulates the behavioral port of the multiplier source file as a component. Whereas, it also permits signal declaration. Mapping its declared signal with the encapsulated component of the behavioral source file values for input and output is possible right within the unit under test.

Meanwhile right under the keyword “begin” situated within the stimulus, the assignment of all possible bits to signals begins which is generated using for…loop and wrapped the signal with assigned values coming from the std_logic_vector. On the other hand the keyword “wait” stop the test indefinitely whereas the “wait for” is used to wait for a specific period of time before the continuation of the next stimulus process.

In a nutshell, the correctness of the multiplier was carried out by the stimulus waveform which was implemented by testbench code.

Below shows the code that generated the waveform:

**Listing 4:**

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

entity MultiplierTb is

-- Port ( );

end MultiplierTb;

architecture Behavioral of MultiplierTb is

component Multiplier is

Generic (datawidth_m:integer:=4);

Port ( aa : in STD_LOGIC_VECTOR (datawidth_m-1 downto 0);

bb : in STD_LOGIC_VECTOR (datawidth_m-1 downto 0);

Product : out STD_LOGIC_VECTOR ((2*datawidth_m-1) downto 0));

end component;

signal datawidth : integer:=4;

signal a_tb : STD_LOGIC_VECTOR (datawidth-1 downto 0);

signal b_tb : STD_LOGIC_VECTOR (datawidth-1 downto 0);

signal Product_tb : STD_LOGIC_VECTOR ((2*datawidth-1) downto 0);

begin

multiplier_tb: Multiplier

generic map (datawidth_m=>datawidth)

port map(

aa=>a_tb,

bb=>b_tb,

Product=>Product_tb);

process

begin

for k in 0 to 2**datawidth-1 loop

a_tb<=std_logic_vector(to_unsigned(k,datawidth));

for h in 0 to 2**datawidth-1 loop

b_tb<=std_logic_vector(to_unsigned(h,datawidth));

wait for 10 ns;

assert(Product_tb = std_logic_vector(to_unsigned(k,datawidth)*to_unsigned(h,datawidth)))

report "test failed for this specified input combination"

severity error ;

end loop;

end loop;

wait;

end process;

end Behavioral;

In these lines of code, I have used for..loop to generate and apply every possible input combination to be assigned to each signals for the multiplication purpose.

Figure 1.3 Waveform for Multiplier

**Conclusion**

In this article, I have shown how to implement both ripple carry adder and parameterizable multiplier for addition and multiplication of binary numbers to get correct products. I have shown the usefulness of the generic, for…loop and constrained vector arrays.

Conclusively, the correctness of this code has been tested both on simulation and the FPGA board given all the necessary binary outputs correctly.

great , thanks for sharing.

ReplyDeleteYou are welcome

Delete