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.
3 Comments
is this function working for std_logic type???
ReplyDeleteis it possible to do division or modulus operation in xilinx ise without using any function or any user own logic codes???
ReplyDelete@rourab : Why do you want to divide std_logic types. You can then use some other simple code to get the result.
ReplyDeleteThe division operator available in vhdl has some limitations.But in Xilinx, you can use the "divider generator" IP core for division if you want.