Using integers for counters in synthesis

  • Thread starter Benjamin Couillard
  • Start date
B

Benjamin Couillard

Hi everyone,

I have a simple question. Assuming we have this process :


MY_PROCESS : process(CLK)
variable cnt : natural range 0 to 255;
begin
if rising_edge(CLK) then
output_signal <= '0';
if (srst = '1') then
cnt := 0;
else
if (cnt = 100) then
output_signal <= '1';
end if;
cnt := cnt + 1;
end if;
end if;
end process;

In simulation, I will get an error at the rising edge of CLK when cnt
is 255. However, what happens in synthesis? Will the synthesizer add
logic to prevent cnt from wrapping aroung ? Or will it simply
implement the "usual" wraparound behavior? Is it synthesizer
specific?

Best regards.

Benjamin
 
Joined
Mar 10, 2008
Messages
348
Reaction score
0
Hi Benjamin

The synthesizer will use 8 f/fs to implement the counter and hence will do the "wraparound" automaticly.

How must you use this code:

if cnt < 255 then
cnt := cnt+1;
else
cnt := 0;
end if;

in order to perform a simulation

Your welcome
Jeppe
 
T

Tricky

Hi everyone,

I have a simple question. Assuming we have this process :

MY_PROCESS : process(CLK)
variable cnt : natural range 0 to 255;
begin
   if rising_edge(CLK) then
    output_signal <= '0';
    if (srst = '1') then
      cnt := 0;
   else
    if (cnt = 100) then
       output_signal <= '1';
   end if;
   cnt := cnt + 1;
   end if;
  end if;
end process;

In simulation, I will get an error at the rising edge of CLK when cnt
is 255. However, what happens in synthesis? Will the synthesizer add
logic to prevent cnt from wrapping aroung ? Or will it simply
implement the "usual" wraparound behavior? Is it synthesizer
specific?

Best regards.

Benjamin

From my experience, counters like this will just wrap in synthesis.
The error you get is more to do with the VHDL type system rather than
how it works on hardware. It is one danger of the VHDL types, but it
might just be safer to stick with an Unsigned type in your code.

Personally, If I want wrapping behaviour I use and unsigned, but if I
always reset at a specific number, Ill use an integer.
 
M

Martin Thompson

Benjamin Couillard said:
Hi everyone,

I have a simple question. Assuming we have this process :


MY_PROCESS : process(CLK)
variable cnt : natural range 0 to 255;
begin
if rising_edge(CLK) then
output_signal <= '0';
if (srst = '1') then
cnt := 0;
else
if (cnt = 100) then
output_signal <= '1';
end if;
cnt := cnt + 1;
end if;
end if;
end process;

In simulation, I will get an error at the rising edge of CLK when cnt
is 255.

Quite right too, you're trying to push 256 into that variable and
you've said "it can't happen" when you defined the range.
However, what happens in synthesis? Will the synthesizer add
logic to prevent cnt from wrapping aroung ? Or will it simply
implement the "usual" wraparound behavior? Is it synthesizer
specific?

In theory it's completely undefined - you've told the synthesiser that
that variable can't be bigger than 255, so if you try and make it so,
the synthesiser is probably within its rights to generate logic that
shorts the power supplies and makes magic smoke issue forth from your
FPGA :)

In reality, no synthesiser I know of would implement this as anything
other than an 8 bit counter which wraps around.

HOWEVER... in order to keep your simulation matching your synthesis
(which IMHO you must do), you should either:

1) Use an unsigned vector, for which wraparound behaviour is the
defined behaviour on overflow.

2) Put some explicit code in to handle the overflow - the synthesiser
will spot that it is unneeded in your case, and implement the same as
it would've before.

As an aside - if you find yourself using a different maximum for cnt
(say 200 for example), and you don't do option 2) you'll likely find the
synthesiser generating an 8 bit wraparound counter which will still
count up to 255, making your sim and synth completely different...

Cheers,
Martin
 
J

Jan Decaluwe

Martin said:
Quite right too, you're trying to push 256 into that variable and
you've said "it can't happen" when you defined the range.


In theory it's completely undefined - you've told the synthesiser that
that variable can't be bigger than 255, so if you try and make it so,
the synthesiser is probably within its rights to generate logic that
shorts the power supplies and makes magic smoke issue forth from your
FPGA :)

In reality, no synthesiser I know of would implement this as anything
other than an 8 bit counter which wraps around.

HOWEVER... in order to keep your simulation matching your synthesis
(which IMHO you must do), you should either:

1) Use an unsigned vector, for which wraparound behaviour is the
defined behaviour on overflow.

2) Put some explicit code in to handle the overflow - the synthesiser
will spot that it is unneeded in your case, and implement the same as
it would've before.

I agree that you have to fix your code like that, but not for any
synthesis-related reason - simply because it is wrong. The run-time
bound error proves that your there is a mismatch between the model
and the design intent. You would have to fix the code regardless
of whether the code is synthesisable or not.

As an aside - if you find yourself using a different maximum for cnt
(say 200 for example), and you don't do option 2) you'll likely find the
synthesiser generating an 8 bit wraparound counter which will still
count up to 255, making your sim and synth completely different...

Again, I find this a very dangerous way of putting it. Now newbies
may think that they should avoid integers because of sim/synth
mismatches, which simply do not exist. It is meaningless to talk
about mismatches beyond a simulation error.

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a HDL: http://www.myhdl.org
VHDL development, the modern way: http://www.sigasi.com
Analog design automation: http://www.mephisto-da.com
World-class digital design: http://www.easics.com
 
A

Andy Peters

Hi everyone,

I have a simple question. Assuming we have this process :

MY_PROCESS : process(CLK)
variable cnt : natural range 0 to 255;
begin
   if rising_edge(CLK) then
    output_signal <= '0';
    if (srst = '1') then
      cnt := 0;
   else
    if (cnt = 100) then
       output_signal <= '1';
   end if;
   cnt := cnt + 1;
   end if;
  end if;
end process;

In simulation, I will get an error at the rising edge of CLK when cnt
is 255. However, what happens in synthesis? Will the synthesizer add
logic to prevent cnt from wrapping aroung ? Or will it simply
implement the "usual" wraparound behavior? Is it synthesizer
specific?

Best regards.

Benjamin

Put a modulo 256 on the counter:

count : process (clk) is
variable cnt : natural range 0 to 255;
begin
if (srst = '1') then
cnt := 0;
outreg <= '0';
elsif rising_edge(clk) then
if (cnt = 100) then
outreg <= '1';
else
outreg <= '0';
end if;

cnt := (cnt + 1) mod 256;
end if;
end process count;

The synthesis tool will recognize that the modulo is just there to
prevent overflow in simulation and it gets optimized away in the
hardware.

-a
 
A

Andy

2) Put some explicit code in to handle the overflow - the synthesiser
will spot that it is unneeded in your case, and implement the same as
it would've before.

That depends on what code you put in there to "handle the overflow"...

If your resulting code will not allow an overflow of the assignment,
then you are removing the ambiguity caused by the illegal condition of
an overflow. Absent the ambiguity, the synthesis tool will then be
bound to replicate the resulting behavior, which may or may not be the
same as before.

A minor point: "the overflow" occurs only upon the assignment, not on
the increment. It is perfectly legal to add 1 to cnt when cnt is 255
(the result is 256). What is not legal is to take that result and try
to store it back into cnt! For example, (cnt + 1 > 255) is perfectly
legal and meaningful with cnt: natural range 0 to 255. With cnt:
unsigned (7 downto 0), it is also legal, but meaningless and will
always evaluate as false. Using (cnt + 1 > 255) or (cnt - 1 < 0) as a
conditional is an excellent way to efficiently detect a roll-over (by
accessing the carry/borrow bit), but it only works for integer
subtypes, not signed/unsigned.

Andy
 
M

Martin Thompson

Jan Decaluwe said:
I agree that you have to fix your code like that, but not for any
synthesis-related reason - simply because it is wrong. The run-time
bound error proves that your there is a mismatch between the model
and the design intent.

Yes - I didn't mean to imply it was for a synthesis-related issue.

The question asked what would happen - I answered. Then followed up
with:

the implication of "you must do" was intended to be "it's wrong
without it" - but I can see it might not be strong enough. Or maybe I
should've written "to keep your simulation matching your design intent".
You would have to fix the code regardless
of whether the code is synthesisable or not.

Well, yes, if the simulation is dying like that, something is wrong.

I read the question (accurately or not!) to be more "it'll die in
sim, but I reckon it'll be alright in the real hardware, do I need to
bother with it?" - to which I was trying to say "YES!"
Again, I find this a very dangerous way of putting it. Now newbies
may think that they should avoid integers because of sim/synth
mismatches, which simply do not exist.

Well, that certainly wasn't my intent, sorry!
It is meaningless to talk about mismatches beyond a simulation
error.

Yes - assuming your simulation is good enough to show the error.

Cheers,
Martin
 
M

Martin Thompson

Andy said:
That depends on what code you put in there to "handle the overflow"...

OK, yes - assuming the code you put in there makes it wrap around to
zero (which is what I meant by "in your case")
If your resulting code will not allow an overflow of the assignment,
then you are removing the ambiguity caused by the illegal condition of
an overflow. Absent the ambiguity, the synthesis tool will then be
bound to replicate the resulting behavior, which may or may not be the
same as before.

Yes, if you make it saturate for example, the synthesiser (of course)
will add logic to replicate your saturation requirement.

<snip>

Cheers,
Martin
 
R

rickman

Quite right too, you're trying to push 256 into that variable and
you've said "it can't happen" when you defined the range.  


In theory it's completely undefined - you've told the synthesiser that
that variable can't be bigger than 255, so if you try and make it so,
the synthesiser is probably within its rights to generate logic that
shorts the power supplies and makes magic smoke issue forth from your
FPGA :)

In reality, no synthesiser I know of would implement this as anything
other than an 8 bit counter which wraps around.

HOWEVER... in order to keep your simulation matching your synthesis
(which IMHO you must do), you should either:

1) Use an unsigned vector, for which wraparound behaviour is the
defined behaviour on overflow.

2) Put some explicit code in to handle the overflow - the synthesiser
will spot that it is unneeded in your case, and implement the same as
it would've before.

As an aside - if you find yourself using a different maximum for cnt
(say 200 for example), and you don't do option 2) you'll likely find the
synthesiser generating an 8 bit wraparound counter which will still
count up to 255, making your sim and synth completely different...

How exactly would my simulation be different from synthesis if I used
a max of 200 for a counter? If my simulation tries to increment the
counter past 200 it stops! That would not be an issue of different
results, that would be my simulation failing to complete! If my usage
of the counter never pushes it past 200, then the simulation and synth
match.

I think people are making far too big of an issue about this. An HDL
is supposed to be describing hardware, hence the name HDL. If you
take the position that the simulation and synthesis should always
match 10% you can never design anything real. If I have a counter
that is only needed for values of 200 or less and I don't care what
happens when the value is over 200, then case 2 is perfectly ok.

The OP has not responded, but I think he is just asking what the
synthesizer does. I don't think his issue is about what the "correct"
thing to do is.

Rick
 
A

Andy

If you want wrapround from 255 to 0, you want a modular type - as others point
out, numeric_std.unsigned meets your needs.

Or you could make the wrapround explicit using the "mod" operator.
This is more flexible since the "mod" value can be something other than 256.

Most synthesis tools will not accept a modulo or divide operation by a
non-integer power of two. For other values, you have to use a
conditional to test for the pending overflow and take appropriate
actions to prevent it.

Andy
 
M

Martin Thompson

rickman said:
How exactly would my simulation be different from synthesis if I used
a max of 200 for a counter? If my simulation tries to increment the
counter past 200 it stops! That would not be an issue of different
results, that would be my simulation failing to complete! If my usage
of the counter never pushes it past 200, then the simulation and synth
match.

OK, yes, I think I expressed myself badly :)

I was trying to talk about unexpected behaviour, and confused the
issue by talking about mismatches. As I said to Jan, if the
simulation doesn't test far enough, one might get different behaviour
to what one (might) expect (however innaccurate that expectation may be).
I think people are making far too big of an issue about this. An HDL
is supposed to be describing hardware, hence the name HDL. If you
take the position that the simulation and synthesis should always
match 10% you can never design anything real.
^^^
I assume you mean 100% there?
If I have a counter that is only needed for values of 200 or less
and I don't care what happens when the value is over 200, then case
2 is perfectly ok.

Quite so, I never intended to say anything other.
The OP has not responded, but I think he is just asking what the
synthesizer does. I don't think his issue is about what the "correct"
thing to do is.

On re-reading the OP with that in mind, I agree.

Sorry for any confusion caused!

Cheers,
Martin
 
B

Benjamin Couillard

OK, yes, I think I expressed myself badly :)

I was trying to talk about unexpected behaviour, and confused the
issue by talking about mismatches.  As I said to Jan, if the
simulation doesn't test far enough, one might get different behaviour
to what one (might) expect (however innaccurate that expectation may be).


        ^^^
I assume you mean 100% there?


Quite so, I never intended to say anything other.




On re-reading the OP with that in mind, I agree.

Sorry for any confusion caused!

Cheers,
Martin

Thnaks for the answers. My question was mostly out of curiosity, I
tried it with ISE and I got a regular 8-bit wrapround counter.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top