VHDL: Synthesisable code for Dividing two Unsigned numbers

THIS CODE WAS UPDATED ON 19th MARCH 2024!

    Dividing an unsigned number by another in VHDL isnt that simple. The code will synthesis only if the divisor is a power of 2, otherwise it will only work in simulation and not in synthesis.

    That is why we need to implement a divider from scratch. There are several algorithms available for this purpose. I have chosen Restoring Division algorithm in this article.
    
    The divider is written in the format of a VHDL procedure. It takes two variables of unsigned type as inputs and two variables of unsigned type as outputs. 

procedure  divide(variable a,b : in unsigned; variable quotient, remainder : out unsigned) is

First input is the dividend and second one is the divisor, while first output is for the quotient and the second one is for the remainder. All these four inputs and outputs should be of the same size for the divider to work correctly.

If you want to know how this algorithm works in general, read this article: Restoring Division algorithm.

I have written the procedure for the divider and used it directly in a testbench code. Along with testing the divider, the testbench also shows how you can use this procedure in your own project. Let me share the code with you.

Unsigned Division in VHDL with testbench:


--library declarations
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
 
--entity for testbenches are always empty
entity tb_divide is
end tb_divide;
 
architecture behavior of tb_divide is 
 
--procedure for dividing two unsigned numbers.
--'a' is the dividend, 'b' is the divisor, quotient and remainder are the results.
 procedure  divide(variable a,b : in unsigned; variable quotient, remainder : out unsigned) is
    --'a1' will contain the quotient, but is initialized with the dividend
    variable a1 : unsigned(a'length-1 downto 0) := a;  
    variable b1 : unsigned(b'length-1 downto 0) := b;  
    variable p1 : unsigned(b'length downto 0):= (others => '0');  --this will contain the remainder
    variable i : integer:=0;  --loop index for iterations.
    begin
        for i in 0 to b'length-1 loop  --iterate N times for a N bit number
            p1(b'length-1 downto 1) := p1(b'length-2 downto 0); --left shift remainder.
            p1(0) := a1(a'length-1); --msb of a1 is passed to lsb of remainder.
            a1(a'length-1 downto 1) := a1(a'length-2 downto 0); --left shift a.
            p1 := p1-b1; --subtract b from remainder.
            if(p1(b'length) ='1') then  --what is the msb of remainder.
                a1(0) :='0'; 
                p1 := p1+b1;  --if its 1, add back b to remainder
            else
                a1(0) :='1';  --if its 0, set lsb of a1 as high.
            end if;
        end loop;
        --assign the final results.
        quotient := a1;
        remainder := p1(a'length-1 downto 0);    --ignore the msb of p1.    
end procedure;  --END of procedure
    
constant N : integer := 8;  --size of the operands and results.
signal a8,b8,quotient,remainder : unsigned(N-1 downto 0);  

begin
 
-- Stimulus process
stim_proc: process
    variable seed1, seed2 : integer := 1;
    variable rand : real;
    variable int_rand : integer;
    variable a,b,q,r : unsigned(N-1 downto 0); 
begin
    for i in 0 to 20 loop
        --generate a random number for a.
        --Value of 'rand' is between 0 and 1. 
        --Multiply 'rand' by 2^N and then round down to get an integer.
        uniform(seed1, seed2, rand);  
        int_rand := integer(trunc(rand*real(2**N))); 
        a := to_unsigned(int_rand,N);
        --generate a random number for b.
        uniform(seed1, seed2, rand);  
        int_rand := integer(trunc(rand*real(2**N)));
        b := to_unsigned(int_rand,N);
        --call the 'divide' procedure. All inputs and outputs are variables here.
        divide(a,b,q,r);
        --check if the result is correct.
        --if the result is correct, a = b*quotient + remainder;
        assert a = b*q+r report "incorrect result";
        --assign the operands and results to signals so that we can see it in the simulation waveform.
        a8 <= a;
        b8 <= b;
        quotient <= q;
        remainder <= r;
        --wait a bit before trying a new set of inputs. 
        --Otherwise we wont be able to see the different iterations in the simulation waveform.
        wait for 10 ns;
    end loop; 
    wait;  --wait endlessly. We are done with testing!
end process;

end;


Note :- This divide procedure is synthesizable. Note that this code does NOT work for negative numbers, though it can be tweaked a bit to make it work for negative numbers.

Simulation Waveform:


simulation waveform for division of two unsigned number in vhdl


 

Post a Comment

3 Comments

  1. is this function working for std_logic type???

    ReplyDelete
  2. is it possible to do division or modulus operation in xilinx ise without using any function or any user own logic codes???

    ReplyDelete
  3. @rourab : Why do you want to divide std_logic types. You can then use some other simple code to get the result.
    The division operator available in vhdl has some limitations.But in Xilinx, you can use the "divider generator" IP core for division if you want.

    ReplyDelete