Note that the first does not need to have any signals in its sensitivity list, while the second must have clk (and only clk is needed, although having others shouldn't hurt) in order for Cadence Leapfrog VHDL to simulate correctly.
process
begin
wait until (clk'event and clk = '1');
... signal assignments, if-then-else statements, case statements, etc ...
end process;
process (clk)
begin
if (clk'event and clk = '1') then
... signal assignments, if-then-else statements,
case statements, etc ...
end if;
end process;
WARNING: If you assign a value to a signal on a rising edge of clock, but not when reset_l is asserted, see this warning.
(If you tell Design compiler that it cannot use rising edge triggered flip flops with asynchronous set, it can't figure out how to make something functionally equivalent using a rising edge triggered flip flop with asynchronous reset!)
process (reset_l, clk)
begin
if (reset_l = '0') then
... signal assignments ...
elsif (clk'event and clk = '1') then
... signal assignments, if-then-else statements,
case statements, etc ...
end if;
end process;
process (... all signals that are read below ...)
begin
if (... complex condition 1 ...) then
... signal assignments, or more complicated things ...
elsif (... complex condition 2 ...) then
... more statements ...
else
... more statements ...
end if;
end process;
One way to make sure that a value is assigned to signals in every
case is to assign them a "default" value at the very beginning of
the process body, and then only list the exceptions below. Here
is an example, where the value of the signal next_fifo_occupancy
is normally the current fifo_occupancy, but if a read or write
occurs, it should go up or down by one. Note that this code was
written in the context of a design where a read and a write to the
FIFO could not occur simultaneously, so we don't have to worry
about that case. Note that some people consider this bad coding practice, because in their opinion it leads to difficult to understand/maintain code. I am not yet one of them.
library ieee;
use ieee.std_logic_1164.all;
--
-- This is the Synopsys package that defines SIGNED, UNSIGNED, and
-- the arithmetic and comparison functions on them.
--
use ieee.std_logic_arith.all;
signal fifo_occupancy,next_fifo_occupancy :
unsigned (FIFO_ADDRESS_BITS-1 downto 0);
signal read_fifo, write_fifo : std_ulogic;
...
process (fifo_occupancy, read_fifo, write_fifo)
begin
--
-- Assign a "default" value to the signal. Exceptions to this
-- default value are noted below.
--
next_fifo_occupancy <= fifo_occupancy;
if (read_fifo = '1') then
next_fifo_occupancy <= fifo_occupancy - 1;
end if;
if (write_fifo = '1') then
next_fifo_occupancy <= fifo_occupancy + 1;
end if;
end process;
Synopsys didn't complain about it, and synthesized a feedthrough signal where there should have been logic on that path.
I should get the "before" and "after" code from Randy to analyze this some time, or at least post to the net to see if it is a well-known problem.
I believe that the code in question simulated fine under Leapfrog.
Work-around: split up the process into two processes: one that inferred the flip-flops, the other that inferred the combinational logic.
By the way, how _do_ you make such signals one-hot according to Synopsys?
If you have a process sensitive to reset and a rising edge of clock,
then be careful if you assign a value to a signal on a rising edge of
clock, but not when reset is asserted.
Details:
When synthesizing the following entity:
After looking at the behavioral meaning of the VHDL code more
carefully, it makes sense. Why? Because by leaving out any
assignment to data_in_loc in the "if (reset_l = '0') then" part of the
code, you are telling it that you don't want the value to change while
reset_l is asserted. That's what the synthesized circuit does.
Still, it would be nice if it could synthesize the signal data_in_loc
with no dependence on reset_l. Note that this probably won't hurt the
logical behavior of the synthesized circuit, although it does mean
that if data_in_loc is undefined when going into reset, then it remain
undefined all through reset. This would be bad for control signals,
but it could be all right for data signals. If data_in_loc had a
significant amount of combinational logic in its assignment(s), then
the additional dependence on reset_l could make it too slow,
especially since reset_l probably has many loads in a large
design.
Work-around: If you have a process that looks like the above, if there
is a signal that is driven in the "elsif (rising clock edge) then"
part, then it should also be assigned a value in the "if (reset_l =
'0') then" part. This will cause the corresponding register to be
inferred as one with an asynchronous set or reset. If you don't want
this, then you must put such signal assignments in a different
process, one that is not dependent on reset_l.
Do NOT use gated/qualified clocks in your design unless
absolutely mandatory to get a correctly functioning
circuit.
Details:
The Synopsys synthesizer Design Compiler does a great job at taking
into account the desired clock speed for normally clocked registers,
both during synthesis and during static timing analysis after layout
and back annotation.
However, unless you do special timing reports just for the purpose, it
ignores the delay of any combinational paths to and from registers
with gated clock signals. By gated clock signals I mean here at least
those clock pins that are connected to the data outputs of other
registers, which we had several occurrences of in the IPP chip. Most
of them were OK, but the ones that were OK were the ones in which the
designer and several others reviewing the design early on reviewed the
timing very carefully, and there was little or no combinational logic
between the registers with gated clock signals and other logic.
By gated clock signals, I do not mean clock pins attached to the clock
input port through a drive tree of buffers. Those are handled
properly by Synopsys.
Update: The Synopsys product PrimeTime supposedly makes it easier to
include such flip-flops in static timing analysis. I haven't used it
yet.
It should also be possible to analyze such clock in normal Synopsys
DesignTime static timing analysis by defining a clock with the
appropriate source and waveform. Unfortunately, this requires looking
up the clock to output time of the driving flip flop by hand, rather
than having the static timing analysis program determine it for
you.
Don't use "inout" ports in any entity unless the signal has multiple
drivers in the design. If the signal is an output, make it a "buffer"
port.
Design Compiler _can_ modify a clock tree, even if you use
set_dont_touch_network, if there are overloads.
Details:
Craig Horn discovered that clock trees that pass through an entity's
inout port aren't properly protected by the set_dont_touch_network
command. Every part of the clock tree after the inout port was fair
game for Design Compiler to modify. Nasty. This happened with v3.3b,
and we believe that it did not happen in older versions. Our
work-around: Don't use inout ports anywhere in your clock tree.
Note: We weren't using inout ports because we had to, just because it
was more convenient when the signal in question was an output of the
entity, and also read inside the entity. It is easy to avoid doing
this by creating an extra internal signal that is read inside the
entity, and assigning the output of the entity to it. At the time we
were using mode 'out' for these signals, which requires this ugliness.
If you use 'buffer', then you can read signals inside of the entity
without such workarounds.
Margaret also found out that even when there are no inout ports in the
clock network, Synopsys might modify a clock network if there are max
capacitance violations. We are not yet certain that this is what
happened, but it is the most likely explanation. This was also with
v3.3b, and we don't know whether other versions exhibit this problem.
Margaret noticed that a BUF39 drive cell was inserted in a clock tree
before being fed to the RFMT, which at the time of synthesis did not
have a clock tree inside of it, and hence its clock input was driving
the clock pins of at least a couple of hundred flip-flops.
Our work-around: If synthesis says it is fixing max capacitance
violations, check your final clock network to see if it is the same as
your original.
It is still OK to have clock signals that are bits within a
std_ulogic_vector in the design, as long as they are fed to
sub-entities, and you never have a right parenthesis followed by
'event in your source code.
library ieee;
use ieee.std_logic_1164.all;
entity try is
port (
clk : in std_ulogic;
reset_l : in std_ulogic;
data_in : in std_ulogic;
data_out : buffer std_ulogic
);
end try;
architecture behavioral of try is
signal data_in_loc : std_ulogic;
begin
process (reset_l, clk)
begin
if (reset_l = '0') then
data_out <= '0';
elsif (clk'event and clk = '1') then
data_in_loc <= data_in after 2 ns;
data_out <= data_in_loc after 2 ns;
end if;
end process;
end; -- of architecture behavioral of TRY
I would expect data_in_loc to be driven by a flip-flop with no
asynchronous set or reset input, and with its D input connected
directly to data_in. It does synthesize to something with no async
input, but its D input is from a multiplexor, with select input chosen
by reset_l. When reset_l is 0, the multiplexor chooses the current
value of the register (its Q output), and when reset_l is 1, the
multiplexor chooses data_in.