VHDL - Why is it bad practice to not include an else-condition in a "process" block? - vhdl

I'm watching a beginner tutorial on VHDL. The lecturer says that it's bad practice to not include an else-condition inside a "process" block because it will create a latch and is bad for timing in advance circuits. He said that including an else-condition will create a mux instead and is better to use in most case.
Why is that?
snippet from lecture video
Why is a latch design bad for timing and what makes the mux design better?

The point is to make VHDL code that results in the design you want, and the risk is that you will inadvertently create a latch.
There are several basic constructions in VHDL, that can illustrate this.
Mux by process with if-then-else, can be made with this code:
process (all) is -- Mux
begin
if sel = '0' then
z <= a;
else
z <= b;
end if;
end process;
Mux by process with if-then and default assign, can be made with this derived code:
process (all) is -- Mux
begin
z <= b; -- Default b, thus for sel = '1', since no overwrite
if sel = '0' then
z <= a;
end if;
end process;
However, if you want to make a mux, then a better coding style is by continuous assign with this code:
z <= a when (sel = '0') else b;
Finally, what can lead to a latch with a process, is if the resulting output is not assigned in all branches of the code. That can occur, if the if-then does neither have an else, nor a default assign to the output, like this code:
process (all) is -- Latch
begin
if en = '1' then
q <= d;
end if;
end process;
So a good rule when designing combinatorial logic using a process, is to have an initial line that makes a default assignment to the resulting output, for example just assing undefined 'X'. A latch is thereby avoided, and functional verification should catch the undefined 'X', if this is a bug.
Also, remember to check the syntheis report for warnings about created latches, since that is most likely a bug in the design.

Related

Why do incomplete if statements create latches during synthesis in VHDL?

Why is it when we try to synthesize incomplete if statements in VHDL the synthesizer uses latches instead of flip-flops?
An explanation from a digital/circuit standpoint would be greatly appreciated.
The premise of the question is wrong. The latch is not inferred instead of a flip-flop.
Flip-flops are inferred every time a signal goes through a clocked process even with an incomplete IF statement. For example, the following code infers a flip-flop:
process(clock) is
begin
if rising_edge(clock) then
if (A) then
B <= C;
end if;
end if;
end process;
Latches are inferred only in combinatorial logic processes when there is an incomplete IF statement. This is due to the fact that an incomplete if statement requires the storage of information which is not possible with the simpler elements of combinatorial logic (wires and gates).
Short answer: because the behaviour of a latch matches that of an incomplete IF. A register does not.
if (A)
B = C;
If the condition A is true and C changes, the output B follows the input immediately. If A is false B keeps it value. This behavior of the IF statement corresponds with the behavior of a latch. Thus a latch is what is generated.
You can not generate this behaviour with a register.
Unfortunately, I can't answer to oldfart (not enough reputation), so technically the short answer is kinda correct.
But, the long answer has different variables: what kind of design do you implement, what tool do you use and what platform is your target.
E.g. Quartus II 16.1, Cyclone V CSXFC6D6F31C6 such code:
library ieee;
use ieee.std_logic_1164.all;
entity d_latch_test is
port
(
signal clk : in std_logic;
enable : in std_logic;
sr_in : in std_logic;
sr_out : out std_logic
);
end entity;
architecture rtl of d_latch_test is
begin
process (clk)
begin
if (rising_edge(clk)) then
if (enable = '1') then
sr_out <= sr_in;
end if;
end if;
end process;
end rtl;
Quartus Synthesis would not tell you that your code is a latch, but it is a D-flip-flop
But! It has asynchronous input.
So basically you can do a flip-flop from if-statement.

Is VHDL default signal assignment also necessary for variables?

I understand that default signal assignment is useful (even necessary) in VHDL to avoid incomplete assignment and inferred latches. I can't discover whether it is also necessary for variables.
Consider this block of code:
test_sequencer : process(fpga_clock)
variable sequencer_count : unsigned(3 downto 0) := (others => '0');
begin
if rising_edge(fpga_clock) then
start_writing <= start_writing;
start_reading <= start_reading;
sequencer_count := sequencer_count; -- is this line necessary
if not_every_fpga_clock = '1' then
case sequencer_count is
when x"4" =>
start_writing <= '1';
when x"12" =>
start_reading <= '1';
when others =>
null;
end case;
if sequencer_count /= 15 then
sequencer_count := sequencer_count + 1;
end if;
end if;
end if;
end process;
Is the line marked "is this line necessary?" required? I understand that it must be there if sequencer_count is a signal. Is it necessary when sequencer_count is a variable?
First, default assignments only prevent latches if no clock is present - ie: combinational logic.
Within register/flip-flop logic (code following the "if rising_edge(clock)"), default assignments prevent hold conditions - which are a normal part of register logic. A latch will never be produced from code under an "if rising_edge(clock)".
OTOH, what you have I call identity assignment:
start_writing <= start_writing;
start_reading <= start_reading;
sequencer_count := sequencer_count;
Identity assignments are not default assignments and specify feedback explicitly. These do not prevent latches in combinational logic.
A default assignment assigns either a literal value or a value from the output of a combinational logic signal:
start_writing <= '0';
sequencer_count := "0000";
LedState <= LedNext;
Note that for a variable declaration in a process, the initialization is only run when the process is elaborated - which is at the start of time and not each time when the process runs:
variable sequencer_count : unsigned(3 downto 0) := (others => '0');
This is different from subprogram execution that creates and initializes the variables each time it is called.
None of these lines are necessary:
start_writing <= start_writing;
start_reading <= start_reading;
sequencer_count := sequencer_count; -- is this line necessary
None of them do anything at all. In complete assignment and latch inference is only a problem with combination logic. This is (synchronous) sequential logic. You never need to worry about complete assignment with (synchronous) sequential logic.
Why is this? Well, in the case of combinational logic, if you don't have complete assignment, there will be some combination of inputs that results in a path through the process being followed in which an output of the process (a signal driven by it) does not get assigned a value. Any signal will keep its value until a new value is assigned. Therefore, in the case of incomplete assignment, it will be necessary for the resulting circuit to remember (to store) the state of that output. Therefore, some kind of circuit that can store information will be synthesised. That will not be a flip-flop, because there are no clocks, no rising_edge function calls etc; instead, latches will be synthesised to do that remembering. That is doubly bad, because (a) latches are fundamentally bad anyway and (b) your were wanting combinational logic but got sequential. That's a bug.
However, in a (synchronous) sequential circuit, you already have storage. Flip-flops can be considered as 1-bit memories. Therefore, you don't need to ever worry about complete assignment in a (synchronous) sequential process. You are expecting the resulting circuit to be able to store things.
In a synchronous process, with rising_edge(fpga_clock), there is no need for neither default variable assignment nor default signal assignment, and both will hold the value before the rising clock, if there is no new assignment when the process triggers (execute) as a result of the rising clock.
What you may have in mind with respect to inferred latches, is maybe related to a combinatorial process, where a latch can be inferred if some branches of an if statement does not assign to a driven signal, like:
process (d, en, q)
begin
if en = '1' then
q <= d;
end if;
end process;
In this case q is only updated if en is '1', so a latch is inferred to hold the value of q if en is '0'.
As a related comment, it is often bad coding style to use variables to hold state in a sequential (clocked) process, and better to declare a signal for sequencer_count. Reason is that coding style is then the same for all flip-flops, and it is easier to debug since variables are not viewable in typical simulation waveforms.

Execute two chunks of code in sequence but the code itself in parallel

I have a piece of code that needs to be executed after another. For example, I have an addition slv_reg2 <= slv_reg0 + slv_reg1; and then I need the result subtracted from a number.
architecture IMP of user_logic is
signal slv_reg0 : std_logic_vector(0 to C_SLV_DWIDTH-1); --32 bits wide
signal slv_reg1 : std_logic_vector(0 to C_SLV_DWIDTH-1);
signal slv_reg2 : std_logic_vector(0 to C_SLV_DWIDTH-1);
signal slv_reg3 : std_logic_vector(0 to C_SLV_DWIDTH-1);
signal flag : bit := '0';
begin
slv_reg2 <= slv_reg0 + slv_reg1;
flag <= '1';
process (flag)
begin
IF (flag = '1') THEN
slv_reg3 <= slv_reg0 - slv_reg2;
END IF;
end process;
end IMP;
I haven't tested the code above but I would like some feedback if my thought is correct. What is contained in the process doens't need to run in sequence, how can I make this part also run in parallel?
In summary, I have two chunks of code that need to be executed in sequence but the code itselft should run in parallel.
--UPDATE--
begin
slv_regX <= (slv_reg0 - slv_reg1) + (slv_reg2 - slv_reg3) +(slv_reg4 - slv_reg5); --...etc
process(clk) -- Process for horizontal counter
begin
if(rising_edge(clk)) then
if(flag = 1) then
flag <= 0;
end if;
end if;
end process;
It's concurrent, not parallel. Just use intermediate signals
I am afraid your thought process about VHDL is not entirely correct. You acknowledge the first assignment happening 'in parallel', but you must realise that the process is also running concurrently with the rest of the statements. Only what happens inside a process is evaluated sequentially - every time any of the signals in the sensitivity list change.
I need to make a lot of assumptions about what you need, but perhaps you're just after this style:
c <= a + b;
e <= d - c;
The signal e will contain d-(a+b) at all times. If you don't immediately understand why - this is where the difference between concurrent and parallel comes in. It is being continuously evaluated - just like if you'd hook the circuit up with copper wires.
If what you actually need is for something to happen based on a clock - you're really not there yet with your example and I recommend looking up examples and tutorials first. People will be happy to help once you provide VHDL code that is more complete.
Issues in your example
Assuming you are intending to write synthesisable VHDL, there several problems with your code:
Your process sensitivity list is not correct - you would either make it sensitive to only a clock, or to all the input signals to the process.
You are both initialising your 'flag' to '1' and assigning it a '0' in concurrent code, that doesn't make sense.
Signals ..reg0 and ..reg1 are not assigned. If they are inputs, don't declare them as signals.
You have named your signals as if they are anonymous numbered 'registers', but they are not registers, just signals: wires! (if ended up with this style because you are comparing to Verilog - let me argue that the Verilog 'reg' regularly don't make sense as they often end up not being registers.)
Try it
I haven't tested the code above but
You really should. Find code examples, tutorials, go and play!

VHDL behavioural D Flip-Flop with R & S

Hi can any of you with more experience with VHDL Quartus II please set me right on this please.
I have the following Entity and behavioural Architecture for a D Flip-Flop with Set and Reset.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY Q1 IS
PORT (D,R,S,CLK : IN std_logic;
Q : OUT std_logic
);
END ENTITY Q1;
ARCHITECTURE behavioural OF Q1 IS
BEGIN
D_FF : PROCESS (CLK,R,S)
BEGIN
IF R = '0' THEN Q <= '0';
ELSIF S = '0' THEN Q <= '1';
ELSIF (rising_edge(CLK)) THEN Q <= D;
END IF;
END PROCESS D_FF;
END ARCHITECTURE behavioural;
When I compile the code using Quartus II I get the following error message :
Warning (335093): TimeQuest Timing Analyzer is analyzing 1 combinational loops as latches.
I think it is a warning for the incomplete output assignments of the R & S inputs, but when I make a D Flip-Flop latch with only the SET input this error message does not appear when compiled. This leaves me thinking maybe I made an error when writing the architecture? If anyone has any answers or useful info that would be much appreciated.
You have described a clock-edge triggered flip-flop (FF) with both an asynchronous reset and an asynchronous set. Only one of them is supported at the same time because AFAIK, all FFs on Altera FPGAs have only an asynchronous reset.
An asynchronous set is emulated on Altera FPGAs by inverting the FF data input and output and then resetting it to low instead of setting it to high. It looks like this:
Don't overlook the inverter on the D input of the FF. If S is low, then the FF itself is asynchronously reset, but due the negation of the Q output afterwars, it behaves as an asynchronous set of output Q of your entity Q1. If S is high, the FF stores the negated input at the rising clock-edge, which is again negated at the output. As you see, the asynchronous reset port of the FF is already used, and thus, cannot be used for an additional asynchronous reset of your entity Q1.
I recommend to use flip-flops with synchronous set and reset instead:
ARCHITECTURE sync_rs OF Q1 IS
BEGIN
D_FF : PROCESS (CLK)
BEGIN
IF (rising_edge(CLK)) THEN
IF R = '0' THEN Q <= '0';
ELSIF S = '0' THEN Q <= '1';
ELSE Q <= D;
END IF;
END IF;
END PROCESS D_FF;
END ARCHITECTURE sync_rs;
Flip flops in FPGA devices usually have either asynchronous set or reset, but not both, so Altera Quartus tries to make the requested circuit with latches instead of dedicated hardware.
However, for most cases that is not what you want, so instead use flip flops with either asynchronous reset or set, or use synchronous set and and reset as Martin Zabel suggested in his answer.
Note that asynchronous reset have an advantage over synchronous reset in high speed designs, since the asynchronous reset does not add any login in the main synchronous data path, which is usually the critical path for high-speed designs.
Finally, for asynchronous reset, it is a good habit to use two if separate statements, with reset last, so clocking is not dependent on assertion of reset. It is not an issue for a single bit flip flop, but if more signals are controlled in the same process, and reset does not apply to all signals, then clocking should not be dependent on reset for those signal without reset, since that will infer latches. Code like:
D_FF : PROCESS (CLK, R)
BEGIN
IF rising_edge(CLK) THEN
Q <= D;
END IF;
IF R = '0' THEN
Q <= '0';
END IF;
END PROCESS D_FF;
Thanks for the reply, I made the R & S inputs asynchronous on purpose. I have been working through a VHDL text book "Free Range VHDL" and have come across the following question in the Exercises:
The question asks for both inputs to be asynchronous. You say this can be emulated with Altera by inverting the input and output and resetting it to low instead of high. Can you expand on this a little? Thanks

VHDL - Input not used

I have problem with this piece of code, "s" doesn't appear in "Floorplan I/O pins" because it is never used why? How could I solve this problem?
entity tempModule is
port (s : in std_logic;
ss : out std_logic);
end tempModule;
architecture tempModule_Behavioral of tempModule is
begin
process(s)
begin
if (s = '1') then
ss <= '1';
end if;
end process;
end tempModule_Behavioral;
Are you sure that pin s and ss are in your UCF?
One thing you could try would be to just do:
ss <= s;
That would ensure that it would not be optimized away.
The VHDL design describes a module that drives 'U' (Uninitialized) on output
ss from power up and until input s is '1', and then output ss is '1'
from then on.
Since the 'U' (Uninitialized) value output in the beginning on ss can be
implemented as any value by the simulation tool, it may be implemented as
'1', whereby the output ss is just trivial '1', and the input s is
thereby unused.
So it sounds like the synthesis tool behaviour is as can be expected, but maybe
the module behavior is to be modified, since the modules does not appear to do
anything useful.
You are implementing a COMBINATIONAL circuit, so the COMPLETE truth table must be described.
However, you have only specified ss for s='1', thus the compiler understands that it is OK to simply keep the output high all the time, in which case s is not actually needed.
To specify ss for all possible values of s, try to end your if statement with "else", like this:
if ...;
elsif ...;
else ...;

Resources