std_logic_vector signals in sensitivity list process

S

Steven Kauffmann

Hello all,

I have some questions about how to use std_logic_vector signals in the
sensitivity list of a process.

First of all, is the sensitivity list like a comparator in hardware
and does it continuously checks if the value changes? Or is the
sensitivity list only important when simulating the design?

If I use a std_logic_vector signal in the sensitivity list, are all
the bits of this signal compared or is only one bit(MSB of LSB) used?

Is there a difference between those two sensitivity lists?

process(port_a(4 downto 0))
begin
-- do something
end process

process(port_a(3), port_a(2), port_a(1), port_a(0))
begin
-- do something
end process

Regards

Steven
 
P

paragon.john

Steven,

Sensitivity lists are relevant only in simulation. A synthesizer
should warn you, however, if you have any signals missing from your
sensitivity list, so as to let you know that you may have a simulation/
synthesis mismatch.

I believe your two examples would be dealt with in the same way, you
could also just do the following...

process(port_a)
begin
-- do something
end process

Regards,
John
 
M

Mike Treseler

Steven said:
Is there a difference between those two sensitivity lists?

Yes, one has 5 bits and the other has 4 bits ;)


Note that the use of asynchronous processes is usually optional.
Using a synchronous process template eliminates concerns about
sensitivity lists and many other things.
__
sync_template : process(reset, clock) is
-- declarations here
begin
if reset = '1' then
init_regs;
elsif rising_edge(clock) then
update_regs;
end if;
update_ports;
end process sync_template;
__
-- Mike Treseler
 
S

Steven Kauffmann

Steven,

Sensitivity lists are relevant only in simulation. A synthesizer
should warn you, however, if you have any signals missing from your
sensitivity list, so as to let you know that you may have a simulation/
synthesis mismatch.

So this means that the process below is not working when it's
implemented in hardware this because the sensitivity list is ignored
and so the process will never be updated?

process(port_a)
begin
-- do something
end process;
 
K

kennheinrich

So this means that the process below is not working when it's
implemented in hardware this because the sensitivity list is ignored
and so the process will never be updated?

process(port_a)
begin
-- do something
end process;

Not quite. VHDL is fundamentally a simulation language, which, when
written using certain common styles, allow it to be used as a source
language for hardware synthesis. This code really could have two ways
to interpret it: one in a simulation environment, which is exactly
what the official language definition explains, and one interpretation
as a hardware description, which is fuzzier. The idea behind using
certain common coding styles is to make sure the behaviour of your
code in simulation and synthesis are the same. That's what's meant by
"synthesis/simulation mismatch".

For simulation purposes, a process with a sensitivity list will run
exactly once at initialization (although in no particular order w.r.t.
other processes' initialization steps), and when the signal changes.
If you specify the wrong sensitivity list by accident, your process
won't respond as you expect (either ignoring events on the signal you
wanted to use, or firing at apparently random other times).

Generally, if you just want a process that responds asynchronously,
immediately, to a set of signals, (like if you're writing a simple
logic gate or an asynchronous memory read), you can skip the
sensitivity list altogether and the compiler will figure out the right
sensitivity list automatically, by looking at every signal that gets
read in the process. You want to either specify every signal correctly
or specify no signals at all in the sensitivity list. Otherwise
there's a good chance that you messed up.

Your question about "comparator in hardware" doesn't quite catch the
idea. If you wanted to follow this analogy, think of a process as
specifying some kind of piece of logic that might be a mixture of
clocked and combinatorial. The sensitivity list defines those inputs
which, if they have an event on them, may cause the output to change.
This means that those signals are either directly connected to the
circuit output through gates, or are used as clock input edges. (This
is admittedly a sloppy analogy.)

When you want to write something behind a clocked register (like a
counter, state machine, etc), you typically _only_ specify the clock
signal in the sensitivity list. Then you put the entire body of the
process inside an "if rising_edge(clk)..." statement. The combination
of these two things tells the synthesizer to generate the
combinatorial logic specified inside the "if" statement, with a flop
on each output signal you assign to. This again, is admittedly a
sloppy description of the synthesis process :)

If you write processes that don't follow one of these three styles
(clocked, combinatorial with no sensitivity, or combinatorial with
complete sensitivity), you're either doing the wrong thing (if you're
a beginner) or are trying to do something fancy (if you're a more
advanced user). If you're trying to be fancy as an advanced user,
there's still a good chance you're wrong, at least the first few
times :)

And so as to make sure to answer your last question:

process(port_a)
blah blah...

will run in simulation at initialization and when any subelement on
port_a (or port_a in its entirety) changes. In hardware, as long as
port_a is the only signal you look at inside your process, you should
be generating a simple combinatorial function of port_a. If
"blah_blah_bah" reads signals _other_ than port_a, or doesn't have the
complete sensitivity list (as in the 4 vs 5 signal discrepancy Mike
pointed out), you're most likely generating something which you didn't
want, regardless of whether you're simulating or synthesizing.

Hope this helps,

- Kenn
 
D

Dwayne Dilbeck

The way the sensitivity list is synthesized is going to dependon the tool
being used. Aside from an extra bit in the sensitivity list the two would
function the same. But synthesis could be completely different. In our
synthesis tool the "sensitivity list" is completely ignored in some
situations. We actually have a coding guide for our tool that states how
the sensitivity list will be synthesized based on the code inside the block.

Check to see if your synthesis tool has a coding guide for using sensitivity
lists.
 
K

KJ

Dwayne Dilbeck said:
The way the sensitivity list is synthesized is going to dependon the tool
being used.
The only 'tool dependency' would be because the tool does not conform to the
VHDL LRM.
Aside from an extra bit in the sensitivity list the two would function the
same.
Well, they would likely synthesize to the exact same thing....but the
synthesized result would differ from that of simulation because of the
different signals in the sensitivity list. The 'correct' one would be the
simulation result, the synthesized result would be wrong.
But synthesis could be completely different. In our synthesis tool the
"sensitivity list" is completely ignored in some situations.
Bragging about LRM non-compliance??
We actually have a coding guide for our tool that states how the
sensitivity list will be synthesized based on the code inside the block.
I prefer the approved standards myself as opposed to a vendor's shortcuts.
Check to see if your synthesis tool has a coding guide for using
sensitivity lists.
Check the LRM instead.

I admit that I do prefer the usual synthesizer's ignoring of the sensitivity
list and putting up a warning to indicate when I have an incomplete list or
a signal that does not belong but that not being the standard, but I MUCH
MORE strongly prefer simulation results to match synthesized results.

But by not using processes other than clocked ones where 'clock' (or 'clock'
and 'reset') is the extent of the sensitivity list means I normally don't
even have to bother with this issue at all.

Kevin Jennings
 
D

Dwayne Dilbeck

Bragging about LRM non-compliance??
Uhm...NO....I hate non conformance, but that is a battle I lost a long time
ago.
When ever we have non-conformance it is caused by one of three issues. 1)
We screed up, 2) A competitor screwed up and we now have to match thier
functionality, or 3) the customer requested we have an alterante path that
is not compliant.

The comment to check his vendors RTL style guide was to address items 2 and
3. If his problem is due to item #1, then it has to be fixed. But cases 2
and 3 are more common in my experience. Granted...My company will break LRM
for any customer that waves enough money at us.(As will most EDA companies)
It just drives me crazy when we make non-conformance a default option
becuase a customer wants it.

I have actually seen two seperate companies want LRM non conformance, but
implemented differently. Niether wanted to use a command line switch to
activate it. Both were holding up big money deals until they got thier
enhancement. Nasty.
 
A

Andy

The only 'tool dependency' would be because the tool does not conform to the
VHDL LRM.


Well, they would likely synthesize to the exact same thing....but the
synthesized result would differ from that of simulation because of the
different signals in the sensitivity list. The 'correct' one would be the
simulation result, the synthesized result would be wrong.


Bragging about LRM non-compliance??


I prefer the approved standards myself as opposed to a vendor's shortcuts.


Check the LRM instead.

I admit that I do prefer the usual synthesizer's ignoring of the sensitivity
list and putting up a warning to indicate when I have an incomplete list or
a signal that does not belong but that not being the standard, but I MUCH
MORE strongly prefer simulation results to match synthesized results.

But by not using processes other than clocked ones where 'clock' (or 'clock'
and 'reset') is the extent of the sensitivity list means I normally don't
even have to bother with this issue at all.

Kevin Jennings

Let's face it, the 800 lb gorilla (Synopsys) decided a long time ago
that they were going to ignore sensitivity lists in synthesis, and
everyone else followed suit, because customers (waiving money) wanted
tools that work "just like Synopsys", instead of "just like the LRM".
Ditto for std_logic_arith, etc.

It really galls me that when we requested that Synopsys add a command
line feature (like modelsim) to only compile certain design unit types
found in the file(s) (i.e. only architectures, etc.). They replied
that the LRM prohibited such a practice! One could argue that the LRM
prohibits out of order compilation of units within one file (an ncsim
and modelsim option), and I seriously doubt that interpretation was
intended by the authors, but it says nothing requiring compiling every
design unit in a file.

Andy
 
D

Dwayne Dilbeck

Bragging about LRM non-compliance??
Uhm...NO....I hate non conformance, but that is a battle I lost a long time
ago.
When ever we have non-conformance it is caused by one of three issues. 1)
We screed up, 2) A competitor screwed up and we now have to match thier
functionality, or 3) the customer requested we have an alterante path that
is not compliant.

The comment to check his vendors RTL style guide was to address items 2 and
3. If his problem is due to item #1, then it has to be fixed. But cases 2
and 3 are more common in my experience. Granted...My company will break LRM
for any customer that waves enough money at us.(As will most EDA companies)
It just drives me crazy when we make non-conformance a default option
becuase a customer wants it.

I have actually seen two seperate companies want LRM non conformance, but
implemented differently. Niether wanted to use a command line switch to
activate it. Both were holding up big money deals until they got thier
enhancement. Nasty.
 
S

Steven Kauffmann

Not quite. VHDL is fundamentally a simulation language, which, when
written using certain common styles, allow it to be used as a source
language for hardware synthesis. This code really could have two ways
to interpret it: one in a simulation environment, which is exactly
what the official language definition explains, and one interpretation
as a hardware description, which is fuzzier. The idea behind using
certain common coding styles is to make sure the behaviour of your
code in simulation and synthesis are the same. That's what's meant by
"synthesis/simulation mismatch".

For simulation purposes, a process with a sensitivity list will run
exactly once at initialization (although in no particular order w.r.t.
other processes' initialization steps), and when the signal changes.
If you specify the wrong sensitivity list by accident, your process
won't respond as you expect (either ignoring events on the signal you
wanted to use, or firing at apparently random other times).

Generally, if you just want a process that responds asynchronously,
immediately, to a set of signals, (like if you're writing a simple
logic gate or an asynchronous memory read), you can skip the
sensitivity list altogether and the compiler will figure out the right
sensitivity list automatically, by looking at every signal that gets
read in the process. You want to either specify every signal correctly
or specify no signals at all in the sensitivity list. Otherwise
there's a good chance that you messed up.

Your question about "comparator in hardware" doesn't quite catch the
idea. If you wanted to follow this analogy, think of a process as
specifying some kind of piece of logic that might be a mixture of
clocked and combinatorial. The sensitivity list defines those inputs
which, if they have an event on them, may cause the output to change.
This means that those signals are either directly connected to the
circuit output through gates, or are used as clock input edges. (This
is admittedly a sloppy analogy.)

When you want to write something behind a clocked register (like a
counter, state machine, etc), you typically _only_ specify the clock
signal in the sensitivity list. Then you put the entire body of the
process inside an "if rising_edge(clk)..." statement. The combination
of these two things tells the synthesizer to generate the
combinatorial logic specified inside the "if" statement, with a flop
on each output signal you assign to. This again, is admittedly a
sloppy description of the synthesis process :)

If you write processes that don't follow one of these three styles
(clocked, combinatorial with no sensitivity, or combinatorial with
complete sensitivity), you're either doing the wrong thing (if you're
a beginner) or are trying to do something fancy (if you're a more
advanced user). If you're trying to be fancy as an advanced user,
there's still a good chance you're wrong, at least the first few
times :)

And so as to make sure to answer your last question:

process(port_a)
blah blah...

will run in simulation at initialization and when any subelement on
port_a (or port_a in its entirety) changes. In hardware, as long as
port_a is the only signal you look at inside your process, you should
be generating a simple combinatorial function of port_a. If
"blah_blah_bah" reads signals _other_ than port_a, or doesn't have the
complete sensitivity list (as in the 4 vs 5 signal discrepancy Mike
pointed out), you're most likely generating something which you didn't
want, regardless of whether you're simulating or synthesizing.

Hope this helps,

- Kenn

Yes I want to do something fancy, but it is not working and I think I
know the problem after that I read your post. But I don't know a
solution for it.

As I already mentioned in my first post, I have to do something in a
process when there is an event on a output port of an other component
described in VHDL. That component is a complex algorithm and because I
don't know how many clock pulses it need before its calculation is
ready, I want to use an other process to check if there is an event on
the output port. When there is an event, I know that the calculation
of the algorithm is done.

Because I thought that a sensitivity list wakes up a process when
there's an event on the signals in its list. I write the following
process.

process(output_complex_algorithm)
begin
result_ready <= not(result_ready);
end process;

I thought that when the output of the complex algorithm changed, the
result_ready signal would also change because of the sensitivity list.
This is not working in hardware. The reason for that, I think, is that
the signal output_complex_algorithm is not used in the process, only
in the sensitivity list. The sensitivity list is not a comparator but
these signals are directly connected with some logic as you said. But
because I don't use the signals in the sensitivity list, it's not
working. Is this correct what I'm saying?

Regards

Steven
 
K

KJ

As I already mentioned in my first post, I have to do something in a
process when there is an event on a output port of an other component
described in VHDL. That component is a complex algorithm and because I
don't know how many clock pulses it need before its calculation is
ready, I want to use an other process to check if there is an event on
the output port.
Then the other component should be generating an 'output_valid' signal
to flag when the calculation is ready. This signal would be true on
each and every clock cycle when there is some new output ready.
When there is an event, I know that the calculation
of the algorithm is done.
'Events' don't synthesize well, because synthesis tools choose to
ignore sensitivity lists. This makes the synthesized result different
than from what you'll see in simulation. Other than to use a
sensitivity list for looking for rising or falling edges of clock
signals you shouldn't bother with them....but do pay attention to and
fix any synthesis warnings that pop out about them (more on that
later).
Because I thought that a sensitivity list wakes up a process when
there's an event on the signals in its list. I write the following
process.

process(output_complex_algorithm)
begin
 result_ready <= not(result_ready);
end process;
Per the VHDL standard, what you've written is correct, the problem is
that synthesis tools do not follow the standard when it comes to
sensitivity lists. They basically ignore the sensitivity list and
simply look at the rest of the code in the process. Given your code
above, your synthesis tool should have generated a warning that signal
'output_complex_algorithm' is not used in the process and will be
ignored. That's the tools way of saying, I'm violating the language
standard but at least I'm telling you about it. The reason it is
ignoring it is because it does not get used anywhere in the process
(other than in the sensitivity list...which the synthesis tool
ignores).

Now take a look at your process from the perspective of something that
has blatantly chosen to ignore the sensitivity list and looks what's
left

result_ready <= not(result_ready);

This will generate a free running, uncontrollable oscillator if
synthesized. Since it is also a combinatorial loop (i.e. feedback
with no intervening flip flop) the synthesis tool should flag this as
a 'warning' as well.

The other type of warning you can get from synthesis tools in regards
to sensitivity lists is an incomplete sensitivity list. In your
process, the signal 'result_ready' was used within the process but was
not in the sensitivity list. Again, the synthesis tool should
generate a warning to that effect. It is doing this because it went
off and determined what IT thinks your process SHOULD be sensitive to
and found that you did not include a signal.

Although the problem is technically with the synthesis tool for
violating the language standard, you have to live with it and design
around it lest you end up with hardware that doesn't work. Peruse the
list of warnings from synthesis and make sure you really understand
their implications. As you should be able to verify, the two types of
warnings that I believe you'll find right now regarding the
sensitivity list must be cleaned up because they represent ways that
the synthesized result is completely different from simulation.
Blaming the synthesis tool will get you nowhere, this behavior has
been there for a looooong time (although don't interpret that to mean
that if you run across other ways that synthesis differs from the
language standard that you shouldn't open a service request, synthesis
tools have lots of bugs).

Synthesis tool 'warnings' can many times be design errors. The only
thing that the synthesis tool considers as an 'error' is something
that prevents it from generating an output file, anything else is a
'warning'. Some examples:
Violating specified timing requirements? 'Warning'.
Completely change the logic by ignoring sensitivity list? 'Warning'
I thought that when the output of the complex algorithm changed, the
result_ready signal would also change because of the sensitivity list.
This is not working in hardware. The reason for that, I think, is that
the signal output_complex_algorithm is not used in the process, only
in the sensitivity list. The sensitivity list is not a comparator but
these signals are directly connected with some logic as you said. But
because I don't use the signals in the sensitivity list, it's not
working. Is this correct what I'm saying?

I think so...get out the fine tooth comb and peruse the warnings that
are no doubt present in the output of the synthesis tool and clean
them all up and you'll be much closer to a working system.

Kevin Jennings
 
A

Andy

Then the other component should be generating an 'output_valid' signal
to flag when the calculation is ready. This signal would be true on
each and every clock cycle when there is some new output ready.


'Events' don't synthesize well, because synthesis tools choose to
ignore sensitivity lists. This makes the synthesized result different
than from what you'll see in simulation. Other than to use a
sensitivity list for looking for rising or falling edges of clock
signals you shouldn't bother with them....but do pay attention to and
fix any synthesis warnings that pop out about them (more on that
later).





Per the VHDL standard, what you've written is correct, the problem is
that synthesis tools do not follow the standard when it comes to
sensitivity lists. They basically ignore the sensitivity list and
simply look at the rest of the code in the process. Given your code
above, your synthesis tool should have generated a warning that signal
'output_complex_algorithm' is not used in the process and will be
ignored. That's the tools way of saying, I'm violating the language
standard but at least I'm telling you about it. The reason it is
ignoring it is because it does not get used anywhere in the process
(other than in the sensitivity list...which the synthesis tool
ignores).

Now take a look at your process from the perspective of something that
has blatantly chosen to ignore the sensitivity list and looks what's
left

result_ready <= not(result_ready);

This will generate a free running, uncontrollable oscillator if
synthesized. Since it is also a combinatorial loop (i.e. feedback
with no intervening flip flop) the synthesis tool should flag this as
a 'warning' as well.

The other type of warning you can get from synthesis tools in regards
to sensitivity lists is an incomplete sensitivity list. In your
process, the signal 'result_ready' was used within the process but was
not in the sensitivity list. Again, the synthesis tool should
generate a warning to that effect. It is doing this because it went
off and determined what IT thinks your process SHOULD be sensitive to
and found that you did not include a signal.

Although the problem is technically with the synthesis tool for
violating the language standard, you have to live with it and design
around it lest you end up with hardware that doesn't work. Peruse the
list of warnings from synthesis and make sure you really understand
their implications. As you should be able to verify, the two types of
warnings that I believe you'll find right now regarding the
sensitivity list must be cleaned up because they represent ways that
the synthesized result is completely different from simulation.
Blaming the synthesis tool will get you nowhere, this behavior has
been there for a looooong time (although don't interpret that to mean
that if you run across other ways that synthesis differs from the
language standard that you shouldn't open a service request, synthesis
tools have lots of bugs).

Synthesis tool 'warnings' can many times be design errors. The only
thing that the synthesis tool considers as an 'error' is something
that prevents it from generating an output file, anything else is a
'warning'. Some examples:
Violating specified timing requirements? 'Warning'.
Completely change the logic by ignoring sensitivity list? 'Warning'


I think so...get out the fine tooth comb and peruse the warnings that
are no doubt present in the output of the synthesis tool and clean
them all up and you'll be much closer to a working system.

Kevin Jennings

Kevin has given excellent advice. While I abhor the synthesis tools'
ignorance of sensitivity lists, at least they do give you warnings
that they cannot completely implement the list's effects. It is also
interesting that they are perfectly willing to generate a latch, which
is an artifact of the behavior due at least partially to the
sensitivity list.

If you try to think about what kind of hardware would be needed to
implement an "event detector", such a thing would be very risky to
design in an FPGA or ASIC without very explicit timing control, which
is something that is generally best left to controlling clocks and
paths between clocked registers.

Besides, in the real implementation, how do you know that the
circuit's output does not change until it magically has the right
answer? Maybe it changes multiple times before settling on the right
answer. What happens if the valid output is the same data twice in a
row (there would be no change to the data, but it represents two valid
pieces of data)? This is the reason you need to have that circuit
either guarantee that output will be valid on specific clock cycles
(usually a fixed cycle delay from the input, etc.), or it must give
you a signal that says the data is or will be valid. Both are valid
design techniques, and are universally used.

Andy
 
B

Brian Drummond

Because I thought that a sensitivity list wakes up a process when
there's an event on the signals in its list. I write the following
process.

process(output_complex_algorithm)
begin
result_ready <= not(result_ready);
end process;

I thought that when the output of the complex algorithm changed, the
result_ready signal would also change because of the sensitivity list.
This is not working in hardware. The reason for that, I think, is that
the signal output_complex_algorithm is not used in the process, only
in the sensitivity list. The sensitivity list is not a comparator but
these signals are directly connected with some logic as you said. But
because I don't use the signals in the sensitivity list, it's not
working. Is this correct what I'm saying?

As KJ says, this is certainly valid VHDL and should do what you expect in
simulation.

But the trouble is that synthesis tools cannot generally translate VHDL into
hardware (this is equally true for all the hardware-C efforts out there; any C
or C++ construct capable of translation into hardware already has a VHDL
equivalent.) Now some of these limitations are due to the current state of the
synthesis tools (whether VHDL or other) but some are fundamental to what is
achievable in hardware.

The upshot is that, for synthesis, you need to "think hardware" first and
foremost, and create something that WILL synthesise. Then and only then, worry
about the sensitivity list to provide the simulator with information to make the
simulation behaviour match the real hardware.

Again as KJ says, the "clean" way in this case is for "complex_algorithm" to
provide a data_valid signal.

But assuming it cannot, (e.g. it's someone else's code) we have to find a way
around the problem.

Which is to detect and announce changes in the output from "complex_algorithm".

Thinking hardware; you are right that a comparator is part of the solution. But
we are detecting changes in the output; therefore comparing the output with an
old copy of the output will work.

You also said that "complex_algorithm" took an unknown number of clock pulses;
implying it is a clocked component, so assume it produces at most one result per
clock. (Two per clock is possible; let's not discuss that here!) Therefore we
can use the same clock to clock a storage element for our "old copy".

So:

process(clk)
begin
if rising_edge(clk) then
old_output <= output_complex_algorithm;
-- new_data_clocked <= new_data; -- ignore, but see below
end if;
end process;

will store the current output until the next cycle, and present the previous
output during this cycle. It only does anything when there is an event on "clk"
therefore that is the only signal required in the sensitivity list.

process (old_output, output_complex_algorithm)
begin
if old_output = output_complex_algorithm then
new_data <= 0;
else
new_data <= '1';
end if;
-- assuming new_data is of type std_logic, or simply
-- new_data <= old_output /= output_complex_algorithm;
-- if new_data is boolean;
end process;

The second process is unclocked; it will simply produce gates. It needs BOTH
signals shown in its sensitivity list.

It will synthesise correctly without them; however if you omit old_output, you
will get incorrect SIMULATION results, because new_data will go '1' when new
data comes in; however in the following cycle, when "old_output" updates, the
simulator will not wake up the process to retract new_data. This is what the
"missing signals in sensitivity list" synthesis warning is about.

It can also be expressed as a single statement; this is simply shorthand for
the above; the tools will work out the sensitivity list from the statement
because what can be expressed in such a statement is strictly limited in scope.

new_data <= old_output /= output_complex_algorithm; -- boolean
-- or for std_logic
new_data <= '0' when old_output = output_complex_algorithm else '1';

Note that "new_data" would normally be stored in a register of its own, as
commented out in the first process; in the current form it is present for less
than a cycle; but guaranteed to be correct at the clock rising_edge, in the SAME
CYCLE as the new input (which may or may not be important to you).

If you want a stored "new_data" output (a clean signal, but one cycle late) you
can combine both processes into one:

process(clk)
begin
if rising_edge(clk) then
old_output <= output_complex_algorithm;
new_data_clocked <= old_output /= output_complex_algorithm;
end if;
end process;

and because you are only interested in the comparator output at the time of the
clock edge, NO other signal is required in the sensitivity list. (Which is good
synchronous design).

The fact that it is one cycle late may not be of any importance to you; simply
use "old_output" downstream instead of "output_complex_algorithm" and it is in
the correct cycle; you have just added one cycle to your pipeline depth.

Sorry if this is a bit pedantic, but I hope that the step by step approach makes
it clear.

- Brian
 
K

kennheinrich

As KJ says, this is certainly valid VHDL and should do what you expect in
simulation.

But the trouble is that synthesis tools cannot generally translate VHDL into
hardware (this is equally true for all the hardware-C efforts out there; any C
or C++ construct capable of translation into hardware already has a VHDL
equivalent.) Now some of these limitations are due to the current state of the
synthesis tools (whether VHDL or other) but some are fundamental to what is
achievable in hardware.

The upshot is that, for synthesis, you need to "think hardware" first and
foremost, and create something that WILL synthesise. Then and only then, worry
about the sensitivity list to provide the simulator with information to make the
simulation behaviour match the real hardware.

Again as KJ says, the "clean" way in this case is for "complex_algorithm" to
provide a data_valid signal.

But assuming it cannot, (e.g. it's someone else's code) we have to find a way
around the problem.

Which is to detect and announce changes in the output from "complex_algorithm".

Thinking hardware; you are right that a comparator is part of the solution. But
we are detecting changes in the output; therefore comparing the output with an
old copy of the output will work.

You also said that "complex_algorithm" took an unknown number of clock pulses;
implying it is a clocked component, so assume it produces at most one result per
clock. (Two per clock is possible; let's not discuss that here!) Therefore we
can use the same clock to clock a storage element for our "old copy".

So:

process(clk)
begin
if rising_edge(clk) then
old_output <= output_complex_algorithm;
-- new_data_clocked <= new_data; -- ignore, but see below
end if;
end process;

will store the current output until the next cycle, and present the previous
output during this cycle. It only does anything when there is an event on "clk"
therefore that is the only signal required in the sensitivity list.

process (old_output, output_complex_algorithm)
begin
if old_output = output_complex_algorithm then
new_data <= 0;
else
new_data <= '1';
end if;
-- assuming new_data is of type std_logic, or simply
-- new_data <= old_output /= output_complex_algorithm;
-- if new_data is boolean;
end process;

The second process is unclocked; it will simply produce gates. It needs BOTH
signals shown in its sensitivity list.

It will synthesise correctly without them; however if you omit old_output, you
will get incorrect SIMULATION results, because new_data will go '1' when new
data comes in; however in the following cycle, when "old_output" updates, the
simulator will not wake up the process to retract new_data. This is what the
"missing signals in sensitivity list" synthesis warning is about.

It can also be expressed as a single statement; this is simply shorthand for
the above; the tools will work out the sensitivity list from the statement
because what can be expressed in such a statement is strictly limited in scope.

new_data <= old_output /= output_complex_algorithm; -- boolean
-- or for std_logic
new_data <= '0' when old_output = output_complex_algorithm else '1';

Note that "new_data" would normally be stored in a register of its own, as
commented out in the first process; in the current form it is present for less
than a cycle; but guaranteed to be correct at the clock rising_edge, in the SAME
CYCLE as the new input (which may or may not be important to you).

If you want a stored "new_data" output (a clean signal, but one cycle late) you
can combine both processes into one:

process(clk)
begin
if rising_edge(clk) then
old_output <= output_complex_algorithm;
new_data_clocked <= old_output /= output_complex_algorithm;
end if;
end process;

and because you are only interested in the comparator output at the time of the
clock edge, NO other signal is required in the sensitivity list. (Which is good
synchronous design).

The fact that it is one cycle late may not be of any importance to you; simply
use "old_output" downstream instead of "output_complex_algorithm" and it is in
the correct cycle; you have just added one cycle to your pipeline depth.

Sorry if this is a bit pedantic, but I hope that the step by step approach makes
it clear.

- Brian

Watch out for one fine point though: a simple check of "output not
equal to input" is not always equivalent to a "computation done" flag.
For matching the behaviour of your simulation/sensitivity example
given, it should work. But if you were, say pipelining some
calculation, and *waiting* for the new result before going into some
other stage of the pipeline, it could fail. If the earlier stage
happened to produce the same result on different inputs, your data
might be correct, the first computation would be complete, but your
change-detect logic wouldn't fire and your next stage would be waiting
forever. In some designs this might be OK; in others it's not.

The unclocked process example that detects a change is also a very
dangerous thing; it has the potential to produce glitches and timing
problems.

I would strongly encourage you to add a "computation done" flag to
your complex calculation block. And it goes without saying that this
should be a synchronous (clocked) flag, just like the output of your
complex block ought to be :)

Brian's advice above to "think hardware" first is right on the money;
a "done flag" is probably the first thought of most hardware guys.

- Kenn
 
B

Brian Drummond

Watch out for one fine point though: a simple check of "output not
equal to input" is not always equivalent to a "computation done" flag.

Now this is true! Either for multiple computations producing the same result,
or the computation outputting an intermediate result. I was taking the stated
problem as the brief, but it's certainly worth asking if it's valid.
The unclocked process example that detects a change is also a very
dangerous thing; it has the potential to produce glitches and timing
problems.

Not "very dangerous" if it is used as I suggested - sampled on the clock edge.
The design tools will either guarantee it is valid then, or report a timing
error, as long as they are used correctly. (If you lie to them about the clock
rate, for example, all bets are off!)

But you are of course correct that other ways of using it - especially, using it
as a clock signal itself - have their attendant dangers.

- Brian
 
K

kennheinrich

Not "very dangerous" if it is used as I suggested - sampled on the clock edge.
The design tools will either guarantee it is valid then, or report a timing
error, as long as they are used correctly. (If you lie to them about the clock
rate, for example, all bets are off!)

You're right; I mis-read your process.

I'm sure this is all old hat to many. But for the benefit of the OP, I
still think you want to add a done flag to the computation unit for
real hardware. More specifically...

There are still more ways the comparator/not equal approach can fail
in the general case. Consider, for example, if the complex logic unit
outputs a large result (say a record type) and not all of the outputs
subelements change synchronously. Maybe one of the portions of the
result is available a clock or two before the others. Then the
comparator may falsely detect "done" when it's not really done, just
in the middle of a partial result. Similarly if the output has don't
care fields in some cases: say a hypothetical controller outputs a
record which can indicate either a "reset" command with an ignored
address, or a "read" command from a specified address. If the address
(which was a don't care) changed spuriously (which conceivably is
legal when the controller is outputting a "reset") it could trigger
downstream action.

Again, these would all be in keeping with the simulation semantics of
the original code, but is not in general a robust way of achieving
system synchronization.

And I can almost guarantee simulation/synthesis mismatch if there are
'X's in the complex output; in simulation, an 'X' will never equal a
'0' but in hardware your gates only know '1' and '0'. So if your sim
initializes the calculation output to 'X', then produces a '1', your
comparator in simulation will detect a change. But if your *hardware*
initializes to '0' and then you calculate a '0', your comparator won't
fire. Mismatch!

Cheers,

- Kenn
 
S

Steven Kauffmann

As KJ says, this is certainly valid VHDL and should do what you expect in
simulation.

But the trouble is that synthesis tools cannot generally translate VHDL into
hardware (this is equally true for all the hardware-C efforts out there; any C
or C++ construct capable of translation into hardware already has a VHDL
equivalent.) Now some of these limitations are due to the current state of the
synthesis tools (whether VHDL or other) but some are fundamental to what is
achievable in hardware.

KJ also wrote something about the synthesize warnings: incomplete
sensitivity list and combinatorial loop.
I receive the warning about the combinatorial loop but not about about
the incomplete sensitivity list. During the place and route process I
receive errors that the signal result_ready is going to be trimmed. If
I turn off the option "trim unconnected signals" the error disappears.
But I don't know if this is a good solution to solve the problem.
The upshot is that, for synthesis, you need to "think hardware" first and
foremost, and create something that WILL synthesise. Then and only then, worry
about the sensitivity list to provide the simulator with information to make the
simulation behaviour match the real hardware.

Again as KJ says, the "clean" way in this case is for "complex_algorithm" to
provide a data_valid signal.

But assuming it cannot, (e.g. it's someone else's code) we have to find a way
around the problem.

As you already mentioned, a data_valid signal is the best solution but
not always possible. Because the code of the complex algorithm is not
written by myself, I prefer not to edit it.
Which is to detect and announce changes in the output from "complex_algorithm".

Thinking hardware; you are right that a comparator is part of the solution. But
we are detecting changes in the output; therefore comparing the output with an
old copy of the output will work.

You also said that "complex_algorithm" took an unknown number of clock pulses;
implying it is a clocked component, so assume it produces at most one result per
clock. (Two per clock is possible; let's not discuss that here!) Therefore we
can use the same clock to clock a storage element for our "old copy".

Like some others already mentioned, a comparator is not always a good
idea because in some cases it won't see a change. In my design such
cases are not ok. I have to see every change, even when the result of
the output is the same as the previous one.

But after reading this thread, I think I have to choose between two
thinks.

1) Adding a data valid signal (best solution but also requires the
most effort because the code is not written myself).

2) Using a comparator and keep in mind that this solution has some
limitations.

[...]
Sorry if this is a bit pedantic, but I hope that the step by step approach makes
it clear.

It's clear for me and is very useful.

Thank you all
 
M

Mike Treseler

Steven said:
During the place and route process I
receive errors that the signal result_ready is going to be trimmed. If
I turn off the option "trim unconnected signals" the error disappears.
But I don't know if this is a good solution to solve the problem.

Any signal or variable that does not
affect an output port is ignored for synthesis.
If the signal "result_ready" is just used for debug,
ignore the warning.
Otherwise, use it to drive a handshake output port.
As you already mentioned, a data_valid signal is the best solution but
not always possible. Because the code of the complex algorithm is not
written by myself, I prefer not to edit it.

I would write a testbench for the "complex" entity,
make the addition, and verify that that everything
still works. If I decide to use existing code,
it becomes my responsibility to maintain it.
1) Adding a data valid signal (best solution but also requires the
most effort because the code is not written myself).

It might not be more effort in the end.
That code has bitten one, and may bite again.


-- Mike Treseler
 
N

neeraj2608

Any signal or variable that does not
affect an output port is ignored for synthesis.
If the signal "result_ready" is just used for debug,
ignore the warning.
Otherwise, use it to drive a handshake output port.

I was wondering how the synthesis tool considers result_ready to be
"unconnected."
Doesn't
result_ready <= not (result_ready);
mean that result_ready is actually connected somewhere (to the input
of the inverter, in this case)?
 

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,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top