VHDL coding tips and tricks: VHDL code for an N-bit Serial Adder with Testbench code

Wednesday, November 1, 2017

VHDL code for an N-bit Serial Adder with Testbench code

Normally an N-bit  adder circuit is implemented using N parallel full adder circuits, simply connected next to each other. The advantage of this is that, the circuit is simple to design and purely combinatorial.

Another way to design an adder, would be to use just one full adder circuit with a flipflop at the carry output. The circuit is sequential with a reset and clock input. In each clock cycle, one bit from each operand is passed to the full adder, and the carry output is fed back as the carry input for the next SUM calculation.

The above block diagram shows how a serial adder can be implemented. The D flipflop is used to pass the output carry, back to the full adder with a clock cycle delay.

In this post, I have used a similar idea to implement the serial adder. Though I have used behavioral level approach to write my code, it should be straight forward to understand if you have the basics right.


library ieee;
use ieee.std_logic_1164.all;

--serial adder for N bits. Note that we dont have to mention N here. 
entity serial_adder is
    port(Clk,reset : in std_logic; --clock and reset signal
            a,b,cin : in std_logic;  --note that cin is used for only first iteration.
            s,cout : out std_logic  --note that s comes out at every clock cycle and cout is valid only for last clock cycle.
end serial_adder;

architecture behav of serial_adder is

--intermediate signals.
signal c,flag : std_logic := '0';


--we use variable, so that we need the carry value to be updated immediately.
variable c : std_logic := '0'; 
if(reset = '1') then --active high reset
    s <= '0';
    cout <= c;
    flag <= '0';
elsif(rising_edge(clk)) then
    if(flag = '0') then
        c := cin;  --on first iteration after reset, assign cin to c.
        flag <= '1';  --then make flag 1, so that this if statement isnt executed any more.
    end if; 
    cout <= '0'; 
    s <= a xor b xor c;  --SUM
    c := (and b) or (and b) or (and c);  --CARRY
end if;
end process;

end behav;


USE ieee.std_logic_1164.ALL;

END tb;


    -- Component Declaration for the Unit Under Test (UUT) 
    COMPONENT serial_adder
        port(Clk,reset : in std_logic;
            a,b,cin : in std_logic;
            s,cout : out std_logic

   signal Clk,reset : std_logic := '0';
   signal a,b,cin : std_logic := '0';
   signal s,cout : std_logic;

   -- Clock period definitions
   constant Clk_period : time := 10 ns;


    -- Instantiate the Unit Under Test (UUT)
   uut: serial_adder PORT MAP (Clk,reset,a,b,cin,s,cout);

   -- Clock process definitions
   Clk_process :process
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
        wait until rising_edge(clk);
        reset <= '1';
        wait for 20 ns;
        reset <= '0';
        --add two 4 bit numbers, 1111 + 1101 = 11101
        a <= '1'; b <= '1'; cin <= '1';   wait for 10 ns;
        a <= '1'; b <= '0'; cin <= '0'; wait for 10 ns;
        a <= '1'; b <= '1'; cin <= '0'; wait for 10 ns;
        a <= '1'; b <= '1'; cin <= '0'; wait for 10 ns;
        reset <= '1';
        wait for 10 ns;
        reset <= '0';
        --add two 5 bit numbers, 11011 + 10001 = 101101
        a <= '1'; b <= '1'; cin <= '1';   wait for 10 ns;
        a <= '1'; b <= '0'; cin <= '0'; wait for 10 ns;
        a <= '0'; b <= '0'; cin <= '0'; wait for 10 ns;
        a <= '1'; b <= '0'; cin <= '0'; wait for 10 ns;
        a <= '1'; b <= '1'; cin <= '0'; wait for 10 ns;
        reset <= '1';
        wait for 10 ns;
   end process;


Note that, even though this code works as a N-bit adder, we don't have to mention the value of N directly. The design keeps adding the input bits in a serial way , when the reset is not high. And in each clock cycle we get the corresponding bit on output s. The cin bit is considered to be valid only on the first clock cycle after a low reset. And the cout output bit is considered to be valid only on the first clock cycle after a high reset. After a pair of numbers are added, just apply reset for at least one clock cycle to show the end of inputs.
This way we can add binary numbers of any size without mentioning the value of N specifically.

See the simulation waveform below to understand what I just explained.

The code was simulated and synthesised using Xilinx ISE 14.6 tool.

No comments:

Post a Comment