Unconstrained integers and synthesis

T

Thomas Heller

I have written some code that uses a unconstrained integer
and wonder how (and why) it can be synthesized. Here is the code;
it is an SPI slave receiver which uses an unconstrained output port.
The word size is determined by the instantiation; I connect the
'data_out' signal to an std_logic_vector(11 downto 0).
The code works correctly in the target device; I have not yet
tried to simulate it.

As I said: how is the counter instantiated? Is this valid VHLD
or does it rely on some accidential features of xilinx implementation?
Would it be better to define the valid range of the integer 'bitcount'?

Thanks,
Thomas

<code>
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity spislave is
Port ( sysclock : in STD_LOGIC;
data_out : out STD_LOGIC_VECTOR;
data_strobe : out STD_LOGIC;
sclk : in STD_LOGIC;
mosi : in STD_LOGIC;
cs : in STD_LOGIC);
end spislave;

architecture Behavioral of spislave is

-- universal spi slave receiver, number of bits is determined by
instantiation.

signal sclk_pipe : std_logic_vector(1 downto 0);
signal data_sr : std_logic_vector(data_out'length-1 downto 0);
signal bitcount : integer; -- <===== ?????

begin

process(sysclock)
begin
if rising_edge(sysclock) then

sclk_pipe(0) <= sclk;
sclk_pipe(1) <= sclk_pipe(0);

if cs = '1' then
-- async reset
bitcount <= 0;
elsif sclk_pipe = "01" then
-- rising edge of SCLK detected: increment bitcount, shift data in
bitcount <= bitcount + 1;
data_sr <= data_sr(data_sr'length-2 downto 0) & mosi;

if bitcount = data_out'length-1 then
data_out <= data_sr(data_sr'length-2 downto 0) & mosi;
data_strobe <= '1';
else
data_strobe <= '0';
end if;

end if;

end if;
end process;

end Behavioral;
</code>
 
N

Nicolas Matringe

Le 29/01/2011 17:10, Thomas Heller a écrit :
I have written some code that uses a unconstrained integer
and wonder how (and why) it can be synthesized. Here is the code;
it is an SPI slave receiver which uses an unconstrained output port.
The word size is determined by the instantiation; I connect the
'data_out' signal to an std_logic_vector(11 downto 0).
The code works correctly in the target device; I have not yet
tried to simulate it.

As I said: how is the counter instantiated? Is this valid VHLD
or does it rely on some accidential features of xilinx implementation?
Would it be better to define the valid range of the integer 'bitcount'?

Hi
This is perfectly legal VHDL but bad practice.
Either your synthesis tool is dumb and it implemented a 32-bit counter,
or it is a bit smarter than that and noticed your integer is actually a
natural, or even that it doesn't need to count further than
data_out'length-1.
Anyway you'd better constrain your signal

Nicolas
 
R

rickman

Le 29/01/2011 17:10, Thomas Heller a crit :



Hi
This is perfectly legal VHDL but bad practice.
Either your synthesis tool is dumb and it implemented a 32-bit counter,
or it is a bit smarter than that and noticed your integer is actually a
natural, or even that it doesn't need to count further than
data_out'length-1.
Anyway you'd better constrain your signal

Nicolas

The other advantage of constraining the integer is that it can help
you catch errors. It may seem like perfectly good code now, but if
you make modifications and are still expecting the counter to run in a
given range and it exceeds that range, the simulation will stop and
tell you about the error. This can be very useful as it prevents
things like unintended counter wraparound which can be hard to debug
on a chip! On the other hand, if you want the counter to wrap around,
you need to explain that clearly to the tool by using the mod operator
when you do the addition.

Rick
 
K

KJ

As I said: how is the counter instantiated?  Is this valid VHLD
or does it rely on some accidential features of xilinx implementation?

It's valid code, but you're wasting resources because synthesis will
build a full 32 bit counter. Since your code is the SPI slave, SCLK
and CS are primary inputs so you have no real control over how many
SCLKs you'll actually get. You could get 12...or you could get
12,000,000. The bitcount signal depends only on those two inputs,
nothing else. All 32 bits will be used in the comparison because
those upper XX bits must be checked to make sure they are indeed 0.
Nicolas' statement "Either your synthesis tool is dumb and it
implemented a 32-bit counter..." is incorrect. Synthesis will
generate a full 32 bit counter (not just the 'dumb ones') and it must
do so because that is precisely what you described (don't take my word
for it, try it yourself and look to see that all 32 bits of bitcount
show up...because they are ALL needed in the comparison to see if
bitcount has hit the magic number needed).

Instead you should make the following changes:
- Define bitcount to be "integer range data_out'range"
- Change when bitcount is incremented as shown below. This change
will prevent bitcount from ever exceeding the specified range. This
might not exactly be what you want, since bitcount will stop at
"data_out'high-1" rather than "data_out'high", but you get the idea.
- You might want to consider what will happen in your code if
'data_out' is connected to a non-zero based vector (i.e. connected to
a vector that is "111 downto 100"). Notice how I changed the compare
value for bitcount below.
if bitcount = data_out'length-1 then (Not data_out'high - 1)
data_out <= data_sr(data_sr'length-2 downto 0) & mosi;
data_strobe <= '1';
else
bitcount <= bitcount + 1;
data_strobe <= '0';
end if;

Left as an exercise for you is to work out what you want data_strobe
to do if you do get more than the expected number of SCLKs. Although
bitcount will stop incrementing, you might not want to keep
data_strobe asserted in that situation. Again, maybe your system is
masking this condition, and maybe nothing really needs to be done to
guard against it, but you should consider the possibility and make an
informed design decision about what to do if the SPI master generates
more clocks than you're expecting. Here is a good case where
simulation will allow you to really exercise 'unexpected' conditions
so that you know what your design will actually do when those
conditions occur.

One should always simulate first. Synthesis should be done in
parallel to give you additional information about your design while
your getting the simulation correct. But the first serious synthesis
run should occur after you get the simulation running, not the other
way around. Doing synthesis first and simulating later is quite
possible, many people do it, but I've found that this tends to lead to
'fragile' designs where 'fragile' means that yes it works when the
rest of the system behaves as expected, but when some condition that
wasn't considered occurs, the design does something totally
unreasonable. Better to have a robust design, many times it doesn't
have any real device resource cost.
Would it be better to define the valid range of the integer 'bitcount'?

Always define the range of any integers, without exception.

Kevin Jennings
 
K

KJ

Either your synthesis tool is dumb and it implemented a 32-bit counter,
or it is a bit smarter than that and noticed your integer is actually a
natural, or even that it doesn't need to count further than
data_out'length-1.

There is no information in the design that the synthesis tool could
use to infer that the counter would never exceed data_out'length-1.
The primary inputs of CS and SCLK are (presumably) off chip and come
from some device that could very well generate lotza clockz. A full
32 bit counter would be generated. Where bitcount is used in the
comparison, the upper bits above data_out'high would have to be
checked to insure that they are 0. The way bitcount is defined in the
OP's code, there is nothing preventing bitcount from exceeding the
range of data_out.
Anyway you'd better constrain your signal
Yep

Kevin Jennings
 
D

Dal

Why don't you have the process clocked by the serial clock then resync
the strobe?

This will require an additional clock domain but means your serial
clock is not used as a flip flop input.

Darrin
 
T

Thomas Heller

Am 30.01.2011 10:06, schrieb Dal:
Why don't you have the process clocked by the serial clock then resync
the strobe?

Because the way I do it there is a little noise immunity.
This will require an additional clock domain but means your serial
clock is not used as a flip flop input.

I see no problem with that.
Thomas
 
K

KJ

Ignore part of previous post where I said "Notice how I changed the
compare value for bitcount below", that part was correct in the OP.
Also, the range of bitcount should be "0 to data_out'length - 1" not
"data_out'range" to accomodate non-zero based vectors

KJ
 
D

Dal

Having the serial to parallel converter on the serial clock domain
allows the serial clock to go up to (and slightly exceed) the system
clock frequency. Not an issue if your system clock > 4xserial clock
frequency. What is your max sclk frequency?

It also has the advantage of not having jittery setup and hold times
which can also be covered by STA. As this is for an FPGA having
deterministic setup/hold is not a issue. If it were for an ASIC it
might make characterising setup/hold a little tricky. If you use the
same clocking method for serial transmit you would also get a jittery
clock to output. Again, not a problem if the serial clock is slow wrt
system clock and you don't need constant clock to out times.

Have you got an timing constraint on the mosi pin? The pin has two
destination flops. One should go in a IOB but the other may go into a
slice so could suffer a longish delay. Again not a problem if serial
clock is clock is slow and you have lots of timing margin. Still
worth a constraint to make sure it doesn't end up on the other side of
the device.

I also noticed you have used "cs" synchronously.

Darrin
 
A

Andy

It's valid code, but you're wasting resources because synthesis will
build a full 32 bit counter.  Since your code is the SPI slave, SCLK
and CS are primary inputs so you have no real control over how many
SCLKs you'll actually get.  You could get 12...or you could get
12,000,000.  The bitcount signal depends only on those two inputs,
nothing else.  All 32 bits will be used in the comparison because
those upper XX bits must be checked to make sure they are indeed 0.
Nicolas' statement "Either your synthesis tool is dumb and it
implemented a 32-bit counter..." is incorrect.  Synthesis will
generate a full 32 bit counter (not just the 'dumb ones') and it must
do so because that is precisely what you described (don't take my word
for it, try it yourself and look to see that all 32 bits of bitcount
show up...because they are ALL needed in the comparison to see if
bitcount has hit the magic number needed).

Instead you should make the following changes:
- Define bitcount to be "integer range data_out'range"
- Change when bitcount is incremented as shown below.  This change
will prevent bitcount from ever exceeding the specified range.  This
might not exactly be what you want, since bitcount will stop at
"data_out'high-1" rather than "data_out'high", but you get the idea.
- You might want to consider what will happen in your code if
'data_out' is connected to a non-zero based vector (i.e. connected to
a vector that is "111 downto 100").  Notice how I changed the compare
value for bitcount below.


Left as an exercise for you is to work out what you want data_strobe
to do if you do get more than the expected number of SCLKs.  Although
bitcount will stop incrementing, you might not want to keep
data_strobe asserted in that situation.  Again, maybe your system is
masking this condition, and maybe nothing really needs to be done to
guard against it, but you should consider the possibility and make an
informed design decision about what to do if the SPI master generates
more clocks than you're expecting.  Here is a good case where
simulation will allow you to really exercise 'unexpected' conditions
so that you know what your design will actually do when those
conditions occur.

One should always simulate first.  Synthesis should be done in
parallel to give you additional information about your design while
your getting the simulation correct.  But the first serious synthesis
run should occur after you get the simulation running, not the other
way around.  Doing synthesis first and simulating later is quite
possible, many people do it, but I've found that this tends to lead to
'fragile' designs where 'fragile' means that yes it works when the
rest of the system behaves as expected, but when some condition that
wasn't considered occurs, the design does something totally
unreasonable.  Better to have a robust design, many times it doesn't
have any real device resource cost.


Always define the range of any integers, without exception.

Kevin Jennings

The synthesized length of an integer type object is implementation
dependent, but must be at least 32 bits unless optimization (e.g.
reachability analysis) permits truncation. Every synthesis tool I know
of implements an integer as 32 bits (prior to optimization), but that
could change at any time, on any tool.

There is a difference between the "size" of an unconstrained vector
type and of a base integer type. The type Integer is NOT
unconstrained, rather it is defined, but implementation specific, with
a minimum required numeric value range per the LRM. An unconstrained
vector has truly undefined length, and must be defined somewhere in
the code (during elaboration), either by the associated signal in an
instantiation, or by a default value specification.

Andy
 

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

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top