Sizing a VHDL input port

Status
Not open for further replies.

shaiko

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
Hello,

I'm sizing a VHDL input port with this line of code:
Code:
x: out unsigned ( positive ( floor ( log2 ( real ( y ) ) ) ) downto 0 ) ;
Y is a generic that's defined as:
Code:
y : positive := 8 ;
Given this y, I expect x to be sized as: ( 3 downto 0 ).
However, modelsim 10.4 sizes it to ( 2 downto 0 ).

What's wrong here?
 

What's wrong here?
A floating point rounding issue with Modelsim. The ieee.math_real.log2(8) is slightly less than 3 when Modelsim does the calculation so the ieee.math_real.floor function then truncates it to 2, see transcript below.

# x'high=2
# ieee.math_real.log2(real)=3.000000e+000
# ieee.math_real.log2(real) < 3.0=true
# ieee.math_real.floor(ieee.math_real.log2(real))=2.000000e+000

If you instead use the synthesizable version of log2 which only works with integers, it returns the correct result.
# work.pkg_Vhd_Common.log2=3
# work.pkg_Vhd_Common.log2(7)=2
# work.pkg_Vhd_Common.log2(8)=3
# work.pkg_Vhd_Common.log2(9)=3

Since you are using the log2 to define bit widths, you most likely want to do the ceil(log2()) rather than the floor(log2()).

# work.pkg_Vhd_Common.ceil_log2(7)=3
# work.pkg_Vhd_Common.ceil_log2(8)=3
# work.pkg_Vhd_Common.ceil_log2(9)=4

The ceil_log2() function simply tests the output of log2(x) and if x > 2**log2(x), than it returns log2(x)+1. If not, then it returns log2(x).

Kevin Jennings
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Thanks so much for your help.

I don't want to use the ceil_log2 function. I need the port to be sized exactly to accommodate the desired width.

If you instead use the synthesizable version of log2 which only works with integers, it returns the correct result.
# work.pkg_Vhd_Common.log2=3
# work.pkg_Vhd_Common.log2(7)=2
# work.pkg_Vhd_Common.log2(8)=3
# work.pkg_Vhd_Common.log2(9)=3

1. Is it a standard package?
2. What's the name of the package?
3. If it works with integers it should also work with positives - correct ?
 

I don't want to use the ceil_log2 function. I need the port to be sized exactly to accommodate the desired width.
That's what ceil_log2 will compute, the exact size you need.



1. Is it a standard package?
2. What's the name of the package?
3. If it works with integers it should also work with positives - correct ?
- It is not a standard package. It is something that most folks stumble across with Google.
- You should only input positives to the function...log(0) and log of negatives are not mathematically defined

Here is one source, look at the post from Ray Andraka
http://groups.google.com/forum/#!msg/comp.lang.vhdl/2fpZGRBXDaE/VuIANrvak6AJ

Here is a link to somebody who posts both a 'simpler' form of log2 which is basically what you have posted in this forum. This guy though posted results from Python, did not post his VHDL results (code is posted though).
http://noasic.com/blog/a-simpler-log2-function/

But the oldest reference that I know of is from the venerable FAQ for comp.lang.vhdl at **broken link removed** which lists both a recursive version (which is what I use), as well as the iterative version from Ray Andraka.

Kevin Jennings
 
Last edited:
Here is a link to somebody who posts both a 'simpler' form of log2 which is basically what you have posted in this forum. This guy though posted results from Python, did not post his VHDL results.
http://noasic.com/blog/a-simpler-log2-function/

Kevin, That link does (now) show two versions of the log2 function a floating point and a integer version following the Python one.
 

Kevin, That link does (now) show two versions of the log2 function a floating point and a integer version following the Python one.

Yes, multiple versions of code are shown but there are no results posted for the VHDL code. Only the Python output is shown. What shaiko is seeing with Modelsim is that the ieee.math_real.log2(8) does not exactly come out to 3. As I showed, it comes out to something less...but that value when printed does round off up to 3. Since the noasic.com posting uses the same method, it's possible that it could have the same issue that shaiko is seeing which is that if you take the floor(log2()) you might get a surprise. I haven't tried it with synthesis tools to see what it comes up with.

Kevin Jennings
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
That's what ceil_log2 will compute, the exact size you need.
Since you are using the log2 to define bit widths, you most likely want to do the ceil(log2()) rather than the floor(log2()).
Maybe it'll work in the particular case I presented - but in other cases it'll calculate a result that's 1 bit longer then what I need.
suppose I want to set the boundaries of 14 (binary 1110).
log2 ( 14.0 ) = 3.85...
And
ceil ( 3.85 ) = 4
So...
ceil ( log2 ( 14.0 ) ) = 4 ;

But obviously "1110" is a ( 3 downto 0 ) vector - not a ( 4 downto 0 ) vector.

Please explain what you meant.
 


If 'N' is considered to be the number of possible combinations, then ceil_log2(N) will be correct in every instance. The usage would be:
Code:
signal xyz: unsigned(ceil_log2(N)-1 downto 0);

I wasn't trying to say that ceil_log2 will return the upper bit index, in fact what it returns is the number of bits that you need to represent 'N'. Given the number of bits required, you would use ceil_log2 to compute the upper bit (as I've shown here). The point was that one would not use the floor() function as you had in your original posting.

Kevin Jennings
 

in fact what it returns is the number of bits that you need to represent 'N'.
I don't see how...
Consider that N=4 which is binary: "100" (3 bits total)
ceil_log2 ( 4 ) = 2

but obviously you need 3 bits to represent N - not 2...
 

I don't see how...
Consider that N=4 which is binary: "100" (3 bits total)
ceil_log2 ( 4 ) = 2

but obviously you need 3 bits to represent N - not 2...

What I was trying to say is not that 'N' is the upper end of the range, rather 'N' is the number of possible combinations (i.e. 0 to N-1). So for N=4 possible combinations, the possible combinations are 0, 1, 2 and 3. So you need two bits. If you want 'N' to be the upper limit of the range (i.e. xyz: integer range 0 to N) then the number of possible combinations would be 'N+1'.

Kevin Jennings
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
I'll try to make it clearer
I have a generic number - call it x.
I want to define port y so it will be able to accommodate numbers smaller or equal to x

Therefore, I need a function (or combination of functions) that calculate the binary position of the MSB of x.
For example:
x = 8 ---> "1000". function returns 3
x = 7 ---> "111". function returns 2
x = 2 ---> "10". function returns 1.

My combination of:
Code:
positive ( floor ( log2 ( real ( x ) ) ) )
Does just that!

However, because of a modalism bug it doesn't work correctly...
Help me rewrite a function that does the same thing.
 


It's not a Modelsim bug, it's because Modelsim doesn't have infinite precision floating point numbers! Do the same thing in C/C++/Python/Perl/Tcl/Verilog/etc.. and you'll have the same problem.

K-J has giving you the answer, multiple times. Either use the code posted in the links provided in #4 or something like what I have below.

Code VHDL - [expand]
1
2
3
-- gives you the number of bits required to hold the value (you keep getting stuck here for some reason):
-- e.g x = 8 ---> "1000", there are 4 bits.
integer ( ceil ( log2 ( real (x) ) ) )



Use the following to get the MSB bit position from the number of bits required to fit x

Code VHDL - [expand]
1
2
3
-- gives you the bit position of the most significant bit (refer back to posts #8 & #10 by K-J):
-- e.g. x = 8 ---> "1000", the 1 is located in bit position 3 of a 4-bit wide value.
integer ( ceil ( log2 ( real (x) ) ) ) - 1



I've used something similar in Verilog for years.
 
Last edited:
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
ads-ee,

I tested your code and came up with problems.

First the code that's supposed to return the number of bit required to hold the value:
Code:
-- gives you the number of bits required to hold the value (you keep getting stuck here for some reason):
-- e.g x = 8 ---> "1000", there are 4 bits.
integer ( ceil ( log2 ( real (x) ) ) )
When x=8 the result is 3 (not 4 as you posted)

Now the second one that's supposed to return the MSB bit position:
Code:
-- gives you the bit position of the most significant bit (refer back to posts #8 & #10 by K-J):
-- e.g. x = 8 ---> "1000", the 1 is located in bit position 3 of a 4-bit wide value.
integer ( ceil ( log2 ( real (x) ) ) ) - 1
When x=8 the result is 2 (not 3 as you posted)
 


What part are you not understanding about what I posted?
Example:
If you have... Some_Sig: integer range 0 to N-1 ;

Then...
Number_Of_Bits := ceil_log2(N);
Msb := Number_Of_Bits-1

'N' could of course be a generic input to an entity so that it can be used to define the width of ports like this

Code:
entity My_Entity is generic (N: positive);
port(
   Inp_Integer:    in    natural range 0 to N-1;
   Out_unsigned:   out   unsigned(ceil_log2(N)-1 downto 0)
);
end My_Entity;

Description of ceil_log2 is contained in post #2. Definition of log2 function is contained in post #4.

The only difference from what you say you want is that you said you want 'x' to be the upper end of the range. So all that means is that your 'x' is my 'N-1'. Therefore, my 'N' is your 'x+1' and all you need to do is replace 'N' with 'x+1' in the above.

Kevin Jennings
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
I think I know where the confusion comes from.

Your definition of ceil_log2 is as follows:
Code:
function ceil_log2(x : positive) return natural is 
begin
  if x <= 1 then
     return 0;
  else
     return ceil_log2(x / 2) + 1;
  end if;
end function ceil_log2;

My definition of ceil_log2 (identical to ads-ee's definition from post #13) is:
Code:
ceil ( log2 ( real ( x ) ) ) -- uses the math.real log2 function


Although both implementations have been referred to as "ceil_log2" in this post - they have different functionality and yield different results.

This one satisfies my requirement for what I want to do:
Code:
function ceil_log2(x : positive) return natural is 
begin
  if x <= 1 then
     return 0;
  else
     return ceil_log2(x / 2) + 1;
  end if;
end function ceil_log2;

While this one - does not:
Code:
ceil ( log2 ( real ( x ) ) ) -- uses the math.real log2 function

Am I correct?
 

Your code that you attribute to me is not correct. What I said was: "The ceil_log2() function simply tests the output of log2(x) and if x > 2**log2(x), then it returns log2(x)+1. If not, then it returns log2(x)." The code that you've posted does not implement that function. The following does implement what I described:
Code:
    function ceil_log2 (Arg : positive) return natural is
        variable RetVal:    natural;
    begin
        RetVal := log2(Arg);
        if (Arg > (2**RetVal)) then
            return(RetVal + 1); -- RetVal is too small, so bump it up by 1 and return
        else
            return(RetVal); -- Just right
        end if;
    end function ceil_log2;

I'll also note that the code you posted that you said meets your requirements (as well as the code that you attributed to me) has "ceil_log2(x / 2) + 1" but this is equivalent to "ceil_log2(x)". I don't know why you take the argument and divide it by 2 before taking the log and then adding 1 at the end rather than simply taking the log of the argument.

Also, in your post you said that the following is not correct...
ceil ( log2 ( real ( x ) ) ) -- uses the math.real log2 function

But in an earlier posting you confirmed that ceil(log2(8.0)) was 3 which is correct. On what basis are you saying that the code is not correct?

Kevin Jennings

-- After the fact: I see what you've done. The code that you have posted for ceil_log2 is actually the code for log2. The two are different functions. ceil_log2 calls log2 as I've shown in my code above.
 
Last edited:
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
Post #4
But the oldest reference that I know of is from the venerable FAQ for comp.lang.vhdl at **broken link removed** which lists both a recursive version (which is what I use), as well as the iterative version from Ray Andraka.

This is the recursive version - and you said that you use it. Therefore I attributed it to you and understood that this is how your "ceil_log2" works.
Code:
function ceil_log2(x : positive) return natural is 
begin
  if x <= 1 then
     return 0;
  else
     return ceil_log2(x / 2) + 1;
  end if;
end function ceil_log2;

But in an earlier posting you confirmed that ceil(log2(8.0)) was 3 which is correct. On what basis are you saying that the code is not correct?
On the basis of applying it on the number 7 (instead of 8).
ceil(log2(7)) = 3
7 is "111" so the MSB's is in position 2 (not 3).
 

Post #4


This is the recursive version - and you said that you use it. Therefore I attributed it to you and understood that this is how your "ceil_log2" works.

No, that is the code for log2 (which I use). It is not the code for ceil_log2 (which I described in post #2 and put the actual VHDL in my last post).

Code:
On the basis of applying it on the number 7 (instead of 8). 
ceil(log2(7)) = 3 
7 is "111" so the MSB's is in position 2 (not 3).
You're contradicting yourself. The ceil(log2(7)) does equal 3. Just because you're looking for the MSB does not mean that ceil(log2(7)) should be 2. I already outlined how to compute the MSB.

I think you need to sit down and re-read this thread (at least up to post #4). The log2 function is not the same thing as the ceil_log2 function and neither of those are functions to compute the MSB. However, the MSB is simply the output of the ceil_log2 function minus one. The ceil_log2 function calls the log2 function. The log2 function (that I use) is the recursive version of the one from comp.lang.vhdl FAQ that I posted the link.

Kevin Jennings
 
Reactions: shaiko

    shaiko

    Points: 2
    Helpful Answer Positive Rating
I think you need to sit down and re-read this thread (at least up to post #4).
Really appreciate your patience. I'm doing that with every new message.
Let me ask a series of Yes/No questions - this will help me understand.

Do you agree that your implementation of what you call ceil_log2:
Code:
    function ceil_log2 (Arg : positive) return natural is
        variable RetVal:    natural;
    begin
        RetVal := log2(Arg);
        if (Arg > (2**RetVal)) then
            return(RetVal + 1); -- RetVal is too small, so bump it up by 1 and return
        else
            return(RetVal); -- Just right
        end if;
    end function ceil_log2;

And this combination:
Code:
ceil ( log2 ( real ( x ) ) ) -- uses the math.real log2 function

Will give different results?
 
Last edited:

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…