# VHDL division function

Status
Not open for further replies.

#### shaiko

I use the following VHDL function for division:

Code:
function restoring_divide ( numerator : unsigned ; denominator : unsigned ) return unsigned is
variable temp_numerator : unsigned ( numerator ' range ) := numerator ;
variable temp_denominator : unsigned ( denominator ' range ) := denominator ;
variable temp_remainder : unsigned ( denominator ' length downto 0 ) := ( others => '0' ) ;
begin
for index in 0 to denominator ' length - 1
loop
temp_remainder ( denominator ' length - 1 downto 1 ) := temp_remainder ( denominator ' length - 2 downto 0 ) ;
temp_remainder ( 0 ) := temp_numerator ( numerator ' length - 1 ) ;
temp_numerator ( numerator ' length - 1 downto 1 ) := temp_numerator ( numerator ' length - 2 downto 0 ) ;
temp_remainder := temp_remainder - temp_denominator ;
if ( temp_remainder ( denominator ' length ) = '1' ) then
temp_numerator ( 0 ) := '0' ;
temp_remainder := temp_remainder + temp_denominator ;
else
temp_numerator ( 0 ) := '1' ;
end if ;
end loop ;
return temp_numerator ;
end function restoring_divide ;

The problem is that when the "numerator" and "denumerator" are of different length, the division fails.
I want the denumerator to adjust its length "automatically" to the length of the numerator. for example:
If the numerator is "10000010" and the denumerator is "110" - I want the denumerator to be "padded" with zeroes to fit itself to the bit width of the numerator and become: "00000110"

#### syedshan

Hi

Why dont you convert it into the integer form before dividing, this way you would not have the issue of different lengths...

use numeric_std packgae in ieee
then

Code:
int_vector_signal := (to_integer(temp_numerator));
--and similar for variables. where int_vector_signal is variable of type integer
--After you perform all calucations you can reconvert it back to unsigned.
--Use unsigned(<final_result>, , denominator'length);

Hope this link will help in type conversions

Or else search for 'qualis 1164 packages quick reference card' in google

#### snishanth512

##### Full Member level 3
Algorithm or Flowchart of your program will be more helpful to suggest an idea.

#### shaiko

syedshan,

I want to be able to divide numers larger than 32 bits..

#### syedshan

Hi

Well. I think you will have your denominator and numberator both fixed digits, since you cannot (in synthesizable HDL) have variable lenght signals.
So the padding should not be the problem.
for example if

Code:
den1(3 downto 0)

then you can easily concatenate the "0000" to the left or right ! ( any where you want)

The problem is that when the "numerator" and "denumerator" are of different length, the division fails.
I want the denumerator to adjust its length "automatically" to the length of the numerator. for example:
If the numerator is "10000010" and the denumerator is "110" - I want the denumerator to be "padded" with zeroes to fit itself to the bit width of the numerator and become: "00000110"

Any ways when you find the solution please share it here as well.

#### TrickyDicky

Why not just use the resized function:

Code:
if numerator'length > demonitor'length then
x := resize(denominator, numerator'length);
end if;

PS. I would highly suggest using a divider IP core. Divides without pipelining are very slow.

#### shaiko

Thanks for the input TrickyDicky.
I tried to take care of all the possible situations:
denominator ' length > numerator ' length
denominator ' length < numerator ' length
denominator ' length = numerator ' length
Please review the code. any input is appreciated.

Code:
function restoring_divide ( numerator : unsigned ; denominator : unsigned ) return unsigned is
variable temp_numerator : unsigned ( numerator ' range ) := numerator ;
variable temp_numerator_with_denominator_length : unsigned ( denominator ' range ) := ( others => '0' ) ;
variable temp_denominator : unsigned ( denominator ' range ) := denominator ;
variable temp_denominator_with_numerator_length : unsigned ( numerator ' range ) := ( others => '0' ) ;
variable temp_remainder : unsigned ( denominator ' length downto 0 ) := ( others => '0' ) ;
variable temp_remainder_with_numerator_length : unsigned ( numerator ' length downto 0 ) := ( others => '0' ) ;
begin
if numerator ' length = denominator ' length then
for index in 0 to denominator ' length - 1
loop
temp_remainder ( denominator ' length - 1 downto 1 ) := temp_remainder ( denominator ' length - 2 downto 0 ) ;
temp_remainder ( 0 ) := temp_numerator ( numerator ' length - 1 ) ;
temp_numerator ( numerator ' length - 1 downto 1 ) := temp_numerator ( numerator ' length - 2 downto 0 ) ;
temp_remainder := temp_remainder - temp_denominator ;
if ( temp_remainder ( denominator ' length ) = '1' ) then
temp_numerator ( 0 ) := '0' ;
temp_remainder := temp_remainder + temp_denominator ;
else
temp_numerator ( 0 ) := '1' ;
end if ;
end loop ;
return temp_numerator ;
elsif numerator ' length > denominator ' length then
temp_denominator_with_numerator_length := resize ( denominator , numerator ' length ) ;
for index in 0 to temp_denominator_with_numerator_length ' length - 1
loop
temp_remainder_with_numerator_length ( temp_denominator_with_numerator_length ' length - 1 downto 1 ) := temp_remainder_with_numerator_length ( temp_denominator_with_numerator_length ' length - 2 downto 0 ) ;
temp_remainder_with_numerator_length ( 0 ) := temp_numerator ( numerator ' length - 1 ) ;
temp_numerator ( numerator ' length - 1 downto 1 ) := temp_numerator ( numerator ' length - 2 downto 0 ) ;
temp_remainder_with_numerator_length := temp_remainder_with_numerator_length - temp_denominator ;
if ( temp_remainder_with_numerator_length ( temp_denominator_with_numerator_length ' length ) = '1' ) then
temp_numerator ( 0 ) := '0' ;
temp_remainder_with_numerator_length := temp_remainder_with_numerator_length + temp_denominator ;
else
temp_numerator ( 0 ) := '1' ;
end if ;
end loop ;
return temp_numerator ;
else
temp_numerator_with_denominator_length := resize ( numerator , denominator ' length ) ;
for index in 0 to denominator ' length - 1
loop
temp_remainder ( denominator ' length - 1 downto 1 ) := temp_remainder ( denominator ' length - 2 downto 0 ) ;
temp_remainder ( 0 ) := temp_numerator_with_denominator_length ( temp_numerator_with_denominator_length ' length - 1 ) ;
temp_numerator_with_denominator_length ( temp_numerator_with_denominator_length ' length - 1 downto 1 ) := temp_numerator_with_denominator_length ( temp_numerator_with_denominator_length ' length - 2 downto 0 ) ;
temp_remainder := temp_remainder - temp_denominator ;
if ( temp_remainder ( denominator ' length ) = '1' ) then
temp_numerator_with_denominator_length ( 0 ) := '0' ;
temp_remainder := temp_remainder + temp_denominator ;
else
temp_numerator_with_denominator_length ( 0 ) := '1' ;
end if ;
end loop ;
return temp_numerator_with_denominator_length ;
end if ;
end function restoring_divide ;

Last edited:

#### TrickyDicky

What are you actually trying to acheive with this function? There is already a divide function in numeric_std for signed and unsigned.

#### shaiko

There is already a divide function in numeric_std for signed and unsigned
How is it called ?

a <= b /c;

#### shaiko

But it isn't synthesizable. Mine is...

#### syedshan

Hi
It is synthesizable. But TrickyDicky, it will only generate the Quotient part. and I think Sheiko wants both quotient and remainder or fraction.

#### shaiko

I want the quotient only...but I'm pretty sure that the '/' function - isn't synthesizable.

#### TrickyDicky

It is synthesisable by some tools, but some may not allow it because it is not pipelined. And you will get the same or worse results with your custom divide function (again, because of lack of pipelining). I suggest using the divider IP cores provided by the manufacturer. They allow pipelining and will return quotient and remainder.

#### shaiko

I'm aware of the limitations of pure combinatorial division logic. I don't intend to use it for high throughput applications.
I simply wanted something that's abstract, works correctly and synthesizes with ANY tool...

Other than very low throughput - do you see something wrong with my code above ?

#### TrickyDicky

I havent really looked at it. To my mind you're re writing a function that has already been written and tested to death.
When you say you dont want high throughput - my previous experiments with / function from numeric_std gave me an FMax of 25Mhz on an Arria 2

shaiko

### shaiko

Points: 2

#### K-J

I'm aware of the limitations of pure combinatorial division logic. I don't intend to use it for high throughput applications.
I simply wanted something that's abstract, works correctly and synthesizes with ANY tool...

Other than very low throughput - do you see something wrong with my code above ?
- Besides speed, the other big drawback to simply using '/' is that it will take a lot of logic
- You might look into Googling to get the source code for 'lpm_divide'. This is pipelined and fast (whether you need it or not), doesn't take nearly as much logic as '/', returns quotient and remainder (again, whether you need it or not) and will work with any tool since it doesn't use any special, you'll have the source code.
- You might want to survey which tools actually do not support '/'. There is nothing inherently un-synthesizable about '/', the only reason it wasn't supported (except for the special case of dividing by a power of 2) is because it generates so much logic and is so slow that tool vendors likely figured that there wouldn't be much demand to support it. In any case, simply trying '/' out with the major tools would answer the question about whether or not it is supported by the universe that you consider to be 'all tools'. I suspect though that what you really mean by supported by 'all tools' is really something for which you have source code...in which case 'lpm_divide' will give that to you as well, but there is certainly nothing wrong with having your own hand written code.

I haven't reviewed your code much but since it is all unclocked I suspect that it might be just as large and slow as '/'. What you should do though is benchmark your code against '/' and 'lpm_divide' to see how your code stacks up. Even if you stick with your code, you will likely get some insights to improve what you have. I assume you've at least run it through a testbench to make sure that it really does produce the correct results in all of the corner cases.

Kevin Jennings

shaiko

Points: 2