Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

VHDL division function

Status
Not open for further replies.

shaiko

Advanced Member level 5
Advanced Member level 5
Joined
Aug 20, 2011
Messages
2,644
Helped
303
Reputation
608
Reaction score
297
Trophy points
1,363
Visit site
Activity points
18,302
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"

Please help...
 

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
 

syedshan,

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

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.
 

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.
 

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:

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

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

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

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.
 

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 ?
 

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
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
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
 
  • Like
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top