Concurrent assignments vs. assignments inside a process

S

Sean Durkin

Guest
Hi *,

I'm sure one of you can clear this up:

During debugging recently I discovered a bug in a module of mine: I had
assigned a signal inside of a clocked process, but had also assigned it
elsewhere concurrently (before writing the process, I had assigned it a
different signal).

Now, the result in simulation is as expected: the concurrent assignment
usually "wins", with occasional 'X' in simulation.
But what is unexpected to me is that the synthesis tools did not
complain about this. I would have expected a "multiple drivers"
error/warning or something similar. Why isn't there any?

I always thought that a concurrent signal assignment is more or less
just a less verbose version of a process with the right-hand-side
signals in the sensitivity list. So basically what I had was assignments
to the same signal from two different processes (one sequential one
combinatorial), which should cause multiple drivers warnings. What would
the hardware really do in that case, anyway?

Sean
 
On 7/13/2014 5:13 AM, Sean Durkin wrote:
Hi *,

I'm sure one of you can clear this up:

During debugging recently I discovered a bug in a module of mine: I had
assigned a signal inside of a clocked process, but had also assigned it
elsewhere concurrently (before writing the process, I had assigned it a
different signal).

Now, the result in simulation is as expected: the concurrent assignment
usually "wins", with occasional 'X' in simulation.
But what is unexpected to me is that the synthesis tools did not
complain about this. I would have expected a "multiple drivers"
error/warning or something similar. Why isn't there any?

I always thought that a concurrent signal assignment is more or less
just a less verbose version of a process with the right-hand-side
signals in the sensitivity list. So basically what I had was assignments
to the same signal from two different processes (one sequential one
combinatorial), which should cause multiple drivers warnings. What would
the hardware really do in that case, anyway?

I would agree with what you about a concurrent statement being a
shorthand version of a combinational process. I would have expected a
multiple driver warning too. There may be something odd going on
because one is clocked and the other combinational. But I expect this
is a bug in any case.

--

Rick
 
Am Sonntag, 13. Juli 2014 11:13:58 UTC+2 schrieb Sean Durkin:
assigned a signal inside of a clocked process, but had also assigned it
elsewhere concurrently (before writing the process, I had assigned it a
different signal).

But what is unexpected to me is that the synthesis tools did not
complain about this. I would have expected a "multiple drivers"
error/warning or something similar. Why isn't there any?

I would expect Warning, no Error. In fact this is legal and the resulting hardware is legal, but very likely to do real bad things, as each time you see an X in simulation, your HW might have a bus conflict with shortcut from power supply to ground. Therefore it is good idea to use std_ulogic instead of std_logic to detect those errors in compile phase of your design.

I always thought that a concurrent signal assignment is more or less
just a less verbose version of a process with the right-hand-side

You are right, if you remove the "or less" :). A concurrent signal is a process with right hand side as sensitivity list.

combinatorial), which should cause multiple drivers warnings. What would
the hardware really do in that case, anyway?

Depending on technology and synthesis tool, you have a bus with multiple driver
directly or through some wired-or constructs. A bus with multiple driver is considered legal for technologies with internal tristate buffer, but it is up to you(the designer) to ensure no condition of the bus can occure that damages the device permanently. Therefore be carefule with the "try and error" suggestion of alb. While a lot of technologies and synthesis tools will come up with a solution that is harmless for the device, there is no guarantee of such in general.

regards Thomas
 
Hi Sean,
Sean Durkin <news_MONTH@tuxroot.de> wrote:
[]
During debugging recently I discovered a bug in a module of mine: I had
assigned a signal inside of a clocked process, but had also assigned it
elsewhere concurrently (before writing the process, I had assigned it a
different signal).

I'm assuming your signal is of a resolved type, say std_logic or
std_logic_vector. These types *can* have multiple drivers since they
have a resolution function to resolve the conflict. Nevertheless I would
not recommend resolved types for synthesis unless strictly necessary
(bus), they may hide nasty bugs.

Now, the result in simulation is as expected: the concurrent assignment
usually "wins", with occasional 'X' in simulation.
But what is unexpected to me is that the synthesis tools did not
complain about this. I would have expected a "multiple drivers"
error/warning or something similar. Why isn't there any?

An unresolved signal cannot be synthesized because the synthesis tool
does not have a way to know what would be the output driving the signal
for a specific configuration of its drivers.

A resolved signal allows you to have multiple sources driving the signal
and it would be up to the designer to make sure the result is what it is
expected (think of a bus).

I always thought that a concurrent signal assignment is more or less
just a less verbose version of a process with the right-hand-side
signals in the sensitivity list.

I would rather think they are two different language constructs, each
with its own characteristics. You can infer a register with a concurrent
assignment, but not a latch. Which one you use is a matter of style, as
long as it matches your desired behavior.

So basically what I had was assignments
to the same signal from two different processes (one sequential one
combinatorial), which should cause multiple drivers warnings. What would
the hardware really do in that case, anyway?

If I were you I'd program the device and see what happens (if the target
is a ram/flash based device). Otherwise you can always simulate the
postsynth results and verify it through your testbench (which you should
anyhow).

I'm not sure what the hardware will do when the signal is 'U' or 'X'

Al
 
On Sunday, July 13, 2014 5:13:58 AM UTC-4, Sean Durkin wrote:
During debugging recently I discovered a bug in a module of mine: I had
assigned a signal inside of a clocked process, but had also assigned it
elsewhere concurrently (before writing the process, I had assigned it a
different signal).

Now, the result in simulation is as expected: the concurrent assignment
usually "wins", with occasional 'X' in simulation.
But what is unexpected to me is that the synthesis tools did not
complain about this. I would have expected a "multiple drivers"

error/warning or something similar. Why isn't there any?

You should submit a ticket to the synthesis vendor. Without the code or knowing which tool you're using nobody here can help unless they happen to have run across the exact same problem. But you are correct, you should get a multiple drivers error on this.

A way to catch this sooner (i.e. while you're still in simulation mode) is to use std_ulogic rather than std_logic. That way you'll have the error reported to you either when you first compile the file or when the simulation starts up.

There is no reason to use std_logic in an FPGA design except at the top level for signals such as a data bus that are driven by multiple sources. FPGAs do not allow for this internally, so there is no reason to use std_logic, use the proper type, std_ulogic/std_ulogic_vector.

Kevin Jennings
 
On Monday, July 14, 2014 2:31:46 AM UTC-4, alb wrote:
I'm assuming your signal is of a resolved type, say std_logic or
std_logic_vector. These types *can* have multiple drivers since they
have a resolution function to resolve the conflict. Nevertheless I would
not recommend resolved types for synthesis unless strictly necessary
(bus), they may hide nasty bugs.

There are no nasty bugs to be hidden. Multiple drivers of a signal no longer exist in FPGAs with the exception of I/O pins.

An unresolved signal cannot be synthesized because the synthesis tool
does not have a way to know what would be the output driving the signal
for a specific configuration of its drivers.

This makes absolutely no sense. All of the signals inside an FPGA come from exactly one driver. That is basically the definition of unresolved (i.e std_ulogic, std_ulogic_vector).

A resolved signal allows you to have multiple sources driving the signal
and it would be up to the designer to make sure the result is what it is
expected (think of a bus).

Just don't think of using it in an FPGA design except on the I/O pins.

Kevin Jennings
 
On Monday, July 14, 2014 5:56:30 AM UTC-4, Thomas Stanka wrote:
I would expect Warning, no Error. In fact this is legal and the resulting
hardware is legal,

No, it would be an error, not a warning. If a synthesis tool actually allows two drivers to be connected, there is a bug in the synthesis tool. Since by design they do not, the following that you wrote is completely wrong...

but very likely to do real bad things, as each time you see
an X in simulation, your HW might have a bus conflict with shortcut from power
supply to ground

But the following is sound advice. All internal FPGA signals should be std_ulogic / std_ulogic_vector.

Therefore it is good idea to use std_ulogic instead of
std_logic to detect those errors in compile phase of your design.

Kevin Jennings
 
alb wrote:
A resolved signal allows you to have multiple sources driving the signal
and it would be up to the designer to make sure the result is what it is
expected (think of a bus).
Then why does the synthesis tool ALWAYS issue a "multiple drivers" error
when a (resolved!) signal is being driven from two processes? It just
doesn't if one of the assignments is concurrent and not inside a process.

- signal driven from two processes -> "multiple drivers" error
- signal driven from one process and a concurrent assignment -> nothing

The signal might be resolved, but to 'X'. How is that going to help a
synthesis tool decide what to do? It's not, and that's why I had
expected it to complain.

I always thought that a concurrent signal assignment is more or less
just a less verbose version of a process with the right-hand-side
signals in the sensitivity list.
I would rather think they are two different language constructs, each
with its own characteristics. You can infer a register with a concurrent
assignment, but not a latch. Which one you use is a matter of style, as
long as it matches your desired behavior.
I looked it up in Ashenden's "Designer's Guide":
"Concurrent signal assignment statements are equivalent to sequential
signal assignments contained in process statements."

So that doesn't really help explain anything here, unfortunately. I'm
sure there's something more specific in the LRM...

If I were you I'd program the device and see what happens (if the target
is a ram/flash based device).
Of course I did that already. The concurrent assignment wins. The
question is: why?

> I'm not sure what the hardware will do when the signal is 'U' or 'X'
Neither am I, and that is really the question here.
With 'U' I would assume it just sets everything to '0', because at least
in Xilinx FPGAs everything's initialized to '0' as a default. So that is
more or less "well-defined" and "logical" behaviour. If undriven,
default to '0' (or even optimize away).

Not so much for 'X', don't know how the decision process works there. If
I had the time right now, I'd try using an unresolved signal to see if
that makes any difference in synthesis.

Greetings,
Sean
 
Multiple driver warnings in synthesis are usually triggered by multiple assignments without any 'Z' values being conditionally driven.

If both of your assignments conditionally drive data or 'Z' onto the signal, then some synthesis tools will handle converting the multiple tri-state signals to muxed data, and if that signal is for chip-level IO, synthesis will handle the output enable control (for the implied TS buffer in the IOB).

Depending on the synthesis tool and what options are set, some synthesis tools will convert internal tri-state "busses" into multiplexers, etc. generating an output for single net. Some will even split up bi-directional tri-state busses, and replace them with multiplexers, etc. I don't necessarily recommend using this feature.

Otherwise, I'm not sure what your problem might be.

Andy
 
On 15/07/2014 14:08, Andy wrote:
On Tuesday, July 15, 2014 1:35:40 AM UTC-5, alb wrote:
Interestingly enough you could use a configuration to wrap your architecture with the extra component for error injection *only* during verification and removing it when performing synthesis. A very useful usecase is when you need to verify an EDAC.

You don't even need to use a configuration (which then requires component declarations and instantiations from the top, all the way down to the module of interest) to try this.

If your EDAC module is instantiated as an entity, WITHOUT an architecture specification (e.g. rtl), then, after you compile all your RTL into the simulator, compile a wrapper architecture for your EDAC module. Inside that wrapper, you re-instantiate the module again, but WITH the architecture specification (rtl). Then you can do anything you want between the module and the rest of the design, inside that wrapper architecture. You can modify/monitor interface signals, insert funnctional coverage (OSVVM), and even use hierarchical references to check on signals inside EDAC (like covering the EDAC's FSM state signal).

Andy
Or to make life even easier just use a bit of Tcl to force some errors
in your EDAC code, this is how I tested my EDAC many many years ago. You
only have to learn 3 Modelsim Tcl commands, "force/noforce", "when" and
"examine".

Regards,
Hans
www.ht-lab.com
 
Hi Hans,

HT-Lab <hans64@htminuslab.com> wrote:
[]
If your EDAC module is instantiated as an entity, WITHOUT an
architecture specification (e.g. rtl), then, after you compile all
your RTL into the simulator, compile a wrapper architecture for your
EDAC module. Inside that wrapper, you re-instantiate the module
again, but WITH the architecture specification (rtl). Then you can do
anything you want between the module and the rest of the design,
inside that wrapper architecture. You can modify/monitor interface
signals, insert funnctional coverage (OSVVM), and even use
hierarchical references to check on signals inside EDAC (like
covering the EDAC's FSM state signal).

Or to make life even easier just use a bit of Tcl to force some errors
in your EDAC code, this is how I tested my EDAC many many years ago. You
only have to learn 3 Modelsim Tcl commands, "force/noforce", "when" and
"examine".

The issue with your suggestion is that is not portable and will depend
on the tcl implementation of your simulator. On top of this what Andy
proposed is much more than just force some values; he is suggesting to
implement coverage collection and/or protocol checkers or the likes.

Indeed you may be capable to embed, within the wrapper, a verification
IP to your module that allows you to perform much more than just forcing
signals.
 
Yes, that's it in a nutshell (wrapper architectures).

Doing anything except black box testing on the gate level model generally takes lots of work, and is not often portable between gate level and RTL verification.

What wrapper architectures (and other similar techniques using configurations) are best at is observing internal interfaces and making sure they are operating per spec, sometimes including inserting errors to see how the rest of the system responds. This often has more to do with ensuring a robust, maintainable implementation rather than just a functional implementation.

Andy
 
On Monday, July 14, 2014 6:31:46 PM UTC+12, alb wrote:

I would rather think they are two different language constructs, each
with its own characteristics. You can infer a register with a concurrent
assignment, but not a latch. Which one you use is a matter of style, as
long as it matches your desired behavior.

From IEEE Std 1076.6-2004

6.2.1.2 Level-sensitive storage from concurrent signal assignment

A level-sensitive storage element shall be modeled for a signal that is assigned in a concurrent signal assignment statement that can be mapped to a process that adheres to the rules in 6.2.1.1.

Example 1:

LEV_SENS_7:
Q <= '0' when RESET ='1' else -- This is identical
D when ENABLE; -- to LEV_SENS_1 in 6.2.1.1,

Example 2:

LEV_SENS_8:
With ENABLE select
Q <= D when '1',
Q when others; -- Identical to LEV_SENS_2 in 6.2.1.1,
-- and models combinational logic.

Example 3:

LEV_SENS_9:
with ENABLE select
Q <= D when '1',
unaffected when others;

(There's more).
 
In case anyone's still interested:

This gets even worse in Vivado. Not even driving a std_ulogic from two
different places causes an error or warning during synthesis... The best
you can do is to receive a critical warning, but only under certain
circumstances (as it turns out, it makes a difference if one of the
drivers drives a constant value or not, for whatever reason...).

I've reported it to Xilinx, but as of now they don't believe me that
this is a problem:

http://tinyurl.com/lkzgsgj

I'll be on vacation for awhile now, maybe the problem will have
magically disappeared when I'm back...

Am 13.07.2014 um 11:13 schrieb Sean Durkin:
Hi *,

I'm sure one of you can clear this up:

During debugging recently I discovered a bug in a module of mine: I had
assigned a signal inside of a clocked process, but had also assigned it
elsewhere concurrently (before writing the process, I had assigned it a
different signal).

Now, the result in simulation is as expected: the concurrent assignment
usually "wins", with occasional 'X' in simulation.
But what is unexpected to me is that the synthesis tools did not
complain about this. I would have expected a "multiple drivers"
error/warning or something similar. Why isn't there any?

I always thought that a concurrent signal assignment is more or less
just a less verbose version of a process with the right-hand-side
signals in the sensitivity list. So basically what I had was assignments
to the same signal from two different processes (one sequential one
combinatorial), which should cause multiple drivers warnings. What would
the hardware really do in that case, anyway?

Sean
 
On Thursday, 31 July 2014 21:28:28 UTC+8, Sean Durkin wrote:
In case anyone's still interested:



This gets even worse in Vivado. Not even driving a std_ulogic from two

different places causes an error or warning during synthesis... The best

you can do is to receive a critical warning, but only under certain

circumstances (as it turns out, it makes a difference if one of the

drivers drives a constant value or not, for whatever reason...).



I've reported it to Xilinx, but as of now they don't believe me that

this is a problem:



http://tinyurl.com/lkzgsgj



I'll be on vacation for awhile now, maybe the problem will have

magically disappeared when I'm back...

I've had a similar problem with Altera before, but in my case it had to do with Quartus optimising away the signals when they aren't used in the design (e.g. not read by another signal, or not used as an output, etc.).

Quartus has the bad habit of optimising away (reducing) multiple drivers to an unresolved net, BEFORE checking that the net is unresolved and it has multiple drivers (and therefore should give an error). I'm not sure if this changed for the latest version. For those interested, you can try the following code and see if Quartus incorrectly optimises away the design without giving any errors:

entity test is port(a0,a1:in std_ulogic; q0:eek:ut std_ulogic);
end entity test;

architecture shouldErrorAndNotOptimise of test is
signal q1:std_ulogic;
begin
q0<=a0; -- wire synthesised from a0 to q0. correct behaviour.
q1<=a1; -- assignment to an internal net.
q1<=a0; -- multiple assignment to an unresolved net.
-- should report error here.

--q0<=a1; -- if this line is enabled, Quartus correctly
-- gives an error on multiple drivers driving q0.
end architecture shouldErrorAndNotOptimise;

I wrote this from memory, and have not tested this code on the latest Quartus. But yes, I did have these problems before when using the tool. The reason why Quartus errored out for q0 and not q1 was because q0 was "used" - it was the output of the design, while q1 was an internal signal that got optimised away. Anyway, I still perceive this as a bug in Quartus, as the code is incorrect as per my understanding of the LRM. Quartus should have thrown me an error, as ModelSim correctly did.

Now, to the topic about having multiple drivers to a RESOLVED net.
Altera has partial support for resolution functions (which is good), but there are still problems with the feature. Having multiple drivers on a resolved net is fine; simulation tools usually resolve to an 'X' (or whatever the resolution function resolves to) and this will be correctly displayed in the simulator. For synthesis tools however, I believe they should give either a Warning or a Critical Warning, but should not give an error. At least warn us that they are multiple drivers to a resolved signal. Both Altera and Xilinx choke at this.

For Altera, I think resolved types only work correctly when a custom resolution function is used - when you try to have multiple drivers to a signal of a predefined resolved type (such as std_logic / std_logic_vector), you would, incorrectly, be puked by Quartus with an error. The tool should have invoked the predefined resolution function and automatically resolve the multiple drivers, while also giving us a Critical Warning. Again, I'm not sure if this behaviour changed for the latest version - last I tried this was at least a couple of years back.

Anyway, I have supported your claim in Xilinx's forum. For those who really need this, do rally your support.

-dan
 
On Friday, August 1, 2014 1:28:28 AM UTC+12, Sean Durkin wrote:
In case anyone's still interested:

This gets even worse in Vivado. Not even driving a std_ulogic from two
different places causes an error or warning during synthesis... The best
you can do is to receive a critical warning, but only under certain
circumstances (as it turns out, it makes a difference if one of the
drivers drives a constant value or not, for whatever reason...).

I've reported it to Xilinx, but as of now they don't believe me that
this is a problem:

http://tinyurl.com/lkzgsgj

Your test case you provided to Xilinx demonstrates your issue admirably.

There's actually support for Xilinx's position in the now withdrawn 1076.6-2004,
Section 5, Verification methodology:

"... The process of verifying synthesis results using simulation consists of
applying equivalent inputs to both the original model and synthesized model and
then comparing their outputs to ensure that they are equivalent. Equivalent in
this context means that a synthesis tool shall produce a circuit that is
equivalent at the input, output, and bidirectional ports of the model. ..."

This issue here is that shall is directive. See 1.3 Terminology:

"The word shall indicates mandatory requirements strictly to be followed in
order to conform to the standard and from which no deviation is permitted
(shall equals is required to)."

And note that synthesis only deals with a subset of VHDL:

See 1.1 Scope:

" This standard defines a subset of very high-speed integrated circuit hardware
description language (VHDL) that ensures portability of VHDL descriptions
between register transfer level synthesis tools. Synthesis tools may be
compliant and yet have features beyond those required by this standard. This
standard defines how the semantics of VHDL shall be used, for example, to model
level-sensitive and edge-sensitive logic. It also describes the syntax of the
language with reference to what shall be supported and what shall not be sup-
ported for interoperability.

Use of this standard should minimize the potential for functional simulation
mismatches between models before they are synthesized and after they are
synthesized."

There is no requirement that a synthesis tool provide a valid synthesis output
for an invalid model.

See the title page:

"...
The subset of the VHDL language, which is synthesizable, is described, and
nonsynthesizable VHDL constructs are identified that should be ignored or
flagged as errors."

There are only two errors defined in 1076.6, 6.3 Three-state logic and busses
and 7.1 Attributes. The one on three-state logic pivots on guarded assignment.

And your test case is invalid, you can't have multiple drivers for unresolved
types.

And back to 5. Verification methodology:

"...
The input stimulus shall comply with the following criteria:

a) Input data does not contain metalogical or high-impedance values.

b) Input data may only contain 'H' and 'L' on inputs that are converted to '1'
and '0', respectively."

There's no requirement that any metavalue on internal_sig be evaluated for
matching behavior in top. Resolution can be ignored.

The underlying issue here is that your model is invalid and your asking Xilinx
detect errors where they've never been required to and historically (prior to
reconfigurable FPGAs) it would have been imprudent to synthesize and implement
hardware based on an invalid model. The cost implications would have demanded
you simulate first where the invalid model would be filtered out.

When Daniel also mentions similar issues with a second synthesis vendor the
message here is that you need an RTL synthesis standard, and that if
resurrected 1076.6 might be updated to require further error detection.

Until then you have no leverage. And any standard on synthesis would represent
a consensus between vendors (the same ones you're collectively complaining
about.)
 
On Friday, 1 August 2014 08:09:58 UTC+8, Dio Gratia wrote:
The underlying issue here is that your model is invalid and your asking Xilinx

detect errors where they've never been required to and historically (prior to

reconfigurable FPGAs) it would have been imprudent to synthesize and implement

hardware based on an invalid model. The cost implications would have demanded

you simulate first where the invalid model would be filtered out.



When Daniel also mentions similar issues with a second synthesis vendor the

message here is that you need an RTL synthesis standard, and that if

resurrected 1076.6 might be updated to require further error detection.



Until then you have no leverage. And any standard on synthesis would represent

a consensus between vendors (the same ones you're collectively complaining

about.)

While 1076.6 may not have described about signal resolutions and driving values, the main standard P1076-2008 specifies this very clearly:

-------------------------------------------------------
Section 6.4.2.3 Signal declarations

[scroll down to Pg. 69]
....
A signal may have one or more sources. For a signal of a scalar type, each source is either a driver (see 14.7.2) or an out, inout, buffer, or linkage port of a component instance or of a block statement with which the signal is associated. For a signal of a composite type, each composite source is a collection of scalar sources, one for each scalar subelement of the signal. It is an error if, after the elaboration of a description, a signal has multiple sources and it is not a resolved signal. It is also an error if, after the elaboration of a description, a resolved signal has more sources than the number of elements in the index range of the type of the formal parameter of the resolution function associated with the resolved signal.
-------------------------------------------------------

It specifically mentions "It is an error if, after the elaboration of a description, a signal has multiple sources and it is not a resolved signal."

Therefore, as per my understanding of the LRM, we actually do have some leverage when trying to press vendors to actually comply to the standard. We should (and could) tell them that their tools are not compliant to the standard until they get this fixed. IMHO, wrong code stays wrong, and it would be wrong for vendors to not give any errors, or worse, optimise away the incorrect design.

--
Daniel | www.tauhop.com
~eats, drinks, sleeps, and breathes VHDL
 

Welcome to EDABoard.com

Sponsor

Back
Top