How to define a counter whose width is big enough to hold integer 27?

Hi,
I have a constant N = 27, how to define a counter whose width is big enough to hold integer 27?
Or how to get a constant = log N? Where "log" is a logarithm with base 2.
Thank you.
Weng
Reply to
Weng Tianxiang
Loading thread data ...
The function you want is the ceiling of log base 2. In Verilog this is $clog2(). If you don't have a similar function it's quite easy to make, since it's generally accomplished by shifting the input value right until it becomes zero and counting the shifts required to get there.
--
Gabor
Reply to
GaborSzakacs
Hi Gabor,
I want to use the (log N) to be the width of a counter:
signal Count : unsigned((log N)-1 downto 0); -- it can hold a known largest number N
Thank you.
Weng
Reply to
Weng Tianxiang
What exactly is the issue? ieee.math_real defines a log2 function that can be used to define the upper bound. Actually what you want is ceil(log2(N))
Kevin
Reply to
KJ
I don't think you need a ceiling function. I think you need a floor function and add 1. log2(8) = 3.0, log2(9) = 3.17, both need 4 bits to represent them in binary. A ceiling function will return 3 for 8 and 4 for 9. So it would be
signal Count : unsigned(flog2(N) downto 0);
Writing flog2(N) should be trivial.
--

Rick
Reply to
rickman
Isn't it a floor function that is required? Floor and add one. No?
--

Rick
Reply to
rickman
ceiling(log2(8+1)) = 4;
What's the trouble?
Regards,
Mark
Reply to
Mark Curry
This can work if you add the 1 first, but the number you want is 3. So you have to subtract 1 from this result. Which is simpler?
Personally I prefer the simpler approach of flog2(N) rather than clog2(N+1)-1 to get where this needs to go. flog2 is a very simple function to write. If you use floating point routines for log2 and ceiling you need to then convert to integer. Are there integer functions for these routines or do you need to write them? I guess that wouldn't make sense since log2 either returns a floating point number or does some form of truncation or rounding.
--

Rick
Reply to
rickman
Hi Gabor, KJ, Rich and Mark,
After your posts, I realized that a user-defined function's returned integer value can be used as boundary limit!!! Before the post I didn't know it.
So I decided to accept Gabor's method to write an integer function log2(integer N) in my design so that it can be repeatedly used later for my life.
Thank you.
Weng
Here is the code:
-- = floor of log2(); log2(27) = 5.
function log2(integer: N) return integer is variable K : integer; variable M : integer; -- = M mod 2 begin K := 0; M := N; loop1: while M /= 0 loop M := M mod 2; -- it cannot use M := M srl 2, because N is an integer K := K+1; end loop;
return K; end log2; -- to be debugged
Reply to
Weng Tianxiang
I can't recall the last time I wrote even a simple program that was 100% correct the first time. I think when you debug your program it will need to be M := M / 2;
You might want to make your comment, "it cannot use M := M srl 1, because N is an integer"
--

Rick
Reply to
rickman
Oh yeah, you also need to change "while M /= 0" to "while M > 1". Otherwise you will get a return value of 1 for 1, 2 for 2, 3 for 4, 4 for 8, etc, which are all 1 more than the correct value and not optimal for your use.
--

Rick
Reply to
rickman
Yes, KJ is right. In code, this would look like (I use this very often in synthesizable code):
signal cnt: u_unsigned(positive(ceil(log2(real(N))))-1 downto 0);
Reply to
Daniel Kho
Code like this is why people use Verilog. I'm just sayin'. ;)
Oh, it's also wrong.
--

Rick
Reply to
rickman
Yes, but explicit type conversions are also one of VHDL's strengths. :) It's better to be explicit in your code when it comes to what types you're using, instead of the tool (or language) doing the conversions implicitly for you - and later on you find out that the implicitly conversions aren't what you want.
- dan
Reply to
Daniel Kho
Over the years I have lived on both sides of the fence. I program hardware in strongly typed VHDL but when it comes to software I prefer Forth which has no concept of type. People try to tell me how good strong typing is and I agree that it can catch problems early that would not be cause so easily later on, but the verbosity and complexity of some code is hard to accept. Others just side step that theoretical issues by pointing out the number of errors made which tools can't catch such as the one you wrote. You didn't even address that.
Your code has a logical flaw that allocates one bit too few for any value of N that is a power of 2. I suppose the tools would flag that when you try to assign a vector of a different size to it... unless you make a similar mistake elsewhere in which case you won't find out until in simulation you exercise with the max value. If that doesn't happen you will have a very hard time trying to figure out why the design doesn't work correctly in the device.
I'm not trying to knock your code. I'm trying to point out that strong typing can impact your coding and allow mistakes to be missed because of the verbosity. Much simpler would be to write a small function to calculate a vector index max value that would replace the whole positive(ceil(log2(real(N))))-1 thing.
--

Rick
Reply to
rickman
Yes you're right there, for values of N that is a power of 2. My earlier code should have been: signal cnt: u_unsigned(positive(ceil(log2(real(N+1))))-1 downto 0);
Personally I prefer the simpler approach of flog2(N) rather than clog2(N+1)-1 to get where this needs to go. flog2 is a very simple function to write. If you use floating point routines for log2 and ceiling you need to then convert to integer. Are there integer functions for these routines or do you need to write them? I guess that wouldn't make sense since log2 either returns a floating point number or does some form of truncation or rounding.
Well, I don't mind writing (log2(N+1)-1), though yes, writing a function can make your life easier.
- daniel
Reply to
Daniel Kho
I hope I'm not belaboring the point too much, but it's not (log2(N+1)-1), it's (positive(ceil(log2(real(N+1))))-1) vs. flog2(N).
I think I developed an aversion to the long windiness of VHDL when I was initially learning it and didn't fully understand the typing. Also it was a bit harder back then when "10011" would not be recognized as an SLV and had to be specified as SLV. Trying to convert types all the time in efficient ways was a PITA. So I learned to write my own conversions that did it in a minimum of layers.
VHDL 2008 is better now with a lot of type issues gone. I still like to eliminate long function chains like the floating point calculation used here to count bits.
--

Rick
Reply to
rickman
Have you considered this?
signal Count : integer range 0 to N;
--

Rick
Reply to
rickman
teger
M := M mod 2 is not correct. You want to divide M by 2 (M := M / 2) in stead.
Or, rather than reinventing and debugging the wheel, Google yourself over t o
formatting link
to find the solution. There are two log2 algorithms implemented, one uses recursive calls to a log2 fu nction, the other uses a while loop. Both claim to be synthesizable in wor king with constants, the recursive version I can vouch works with signals a s well (i.e. Log_Sig1
Reply to
KJ
Hi Rick, I just want to 1 for 1, 2 for 2, 3 for 4, 4 for 8, the bit count that is big enough to hold N.
signal Counter : unsigned(log2(N)-1 downto 0);
I don't want to skip "-1", because all unsigned() expressions in my design uses format name(xxx-1 downto 0);
for all integer M mod 2 == M / 2, but latter is better than former.
So actually my design has no error at all!!!
Weng
Reply to
Weng Tianxiang

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.