This article explains how Synthesis identifies clock and other control signals when inferring a Flop from Verilog RTL code.
The discussion in this section is true for all synthesis tools in the world of ASIC/FPGA synthesis.
There might be some differences in the tools in terms of error checking and warnings, but the core inference remains the same.
For a synthesizable Verilog code, the actual code functionality can be thought of as falling in one of the three categories:
(ii) Continuous assignment
(iii) "always" blocks
Inferring a Flop
A flop can only be inferred by an always block, though always block can also infer non-flop elements.
If the sensitivity list of the always block has an edge specification (for example posedge or negedge), this will infer a flop.
If an always block has an edge specification on ANY ONE of the signals in the sensitivity list, it MUST
(A) have edge specification on EACH of the signals in the sensitivity list AND
(B) have at least one signal in the sensitivity list and at most three signals in the sensitivity list
The above conditions are for synthesis inference only.
Simulation or LRM has no such restriction.
always @(posedge sig1 or sig2) // example 1
This is valid Verilog, but will not synthesize, as it violates condition A.
always @(posedge sig1 or negedge sig2) // example 2
This is valid (at least the above code segment) for synthesis.
Once both conditions A and B are determined to have been satisfied, the tool has to identify all of the control signals for the flop.
No Asynchronous Control
If there is only one signal in the sensitivity list, that signal is the clock. That one line is enough to identify the clock and its polarity.
always @(posedge sig1) // example 3
This indicates that sig1 is the clock. The edge on the signal indicates whether the clock is rising edge triggered or falling edge triggered. In the above example, the clock sig1 is rising edge triggered.
If the number of signals is more than one, then besides the clock the other signals are asynchronous set and/or reset.
The sensitivity information of the always block alone is not enough to determine which of these signals is the clock, and which is set or reset.
always @(posedge sig1 or posedge sig2 or posedge sig3) // example 4: 3 signals in sensitivity list
The tool does not know yet which of these signals is the clock or asynchronous set or reset.
always @(posedge sig1 or posedge sig2) // example 5: 2 signals in sensitivity list
The tool does not know which of these signals is the clock and which one is the asynchronous control signal.
Even for the asynchronous control signal, it is not known yet if that signal is a set or a reset.
One Asynchronous Control Signal
For the sake of ease, consider an always block with 2 signals (edge sensitive) in the sensitivity list - as mentioned in example 5.
Within the always block, there should be an if condition, where the if is based on one of the signals mentioned in the sensitivity list:
always @(posedge sig1 or posedge sig2) // example 6
Here, sig1 is an asynchronous control signal so the remaining signal (viz: sig2) is the clock.
Once the tool has determined the clock signal (sig2), it can know its active edge from the edge specification in the always block (positive edge in this case).
The if condition also tells us the active value of the asynchronous signal. In the given example, the active value is High, because the if condition is true for the High Value of sig1. This High value correlates with the posedge specification of sig1 in the always block's sensitivity list.
If these values (condition of if and the edge specified on the sensitivity list) do not agree with each other, it denotes a faulty Verilog code. The synthesized code and RTL simulation will not be the same.
Depending on the tool, it might or might not report. The edge specification on the sensitivity list for an asynchronous block is of no use to a synthesis tool for inferring the circuit. Synthesis tools use the if condition to determine the active value - for the purpose of realizing the circuit.
So by now, the tool has determined the following:
- Clock and its triggering edge
- An asynchronous signal and its active level
The tool still does not know if this asynchronous signal is a reset or a set signal.
For that decision, the tool looks into what is going on inside the if condition:
always @(posedge sig1 or posedge sig2) // example 7
r1 <= 1'b0;
The above code says that sig1 is a reset signal (for r1), because it took the register to 0.
If the register value was being taken to a 1, sig1 would be a set signal.
Two Asynchronous Control Signals
Now, consider an always block with three signals specified in the sensitivity list, as in example 4.
Once again, the tool will look into the first if condition inside the always block to determine one asynchronous signal.
It will will then look into the next if condition inside the always block to determine the second asynchronous signal.
The remaining third signal of the sensitivity list is the clock.
always @(posedge sig1 or posedge sig2 or posedge sig3) // example 8
if (sig1) …..
else if (sig2) ……
This tells us the following:
- sig1 and sig2 are asynchronous control signals.
- the remaining sig3 is the clock signal.
- from the edge of sig3 in the always block's sensitivity list, the tool knows that this clock is rising edge triggered.
- for each of sig1 and sig2, the tool determines:
- their active levels based on the if condition (level High in our example), and then those levels should match with the edge specification in the sensitivity list
- the tool then goes inside the if/else if conditions to determine if this asynchronous control signal is acting as a set or a reset.
- One more thing that the tool infers is: of the two asynchronous control signals, which is higher priority.
The signal that shows up first inside the always block - as the first if condition - is the higher priority. The order of listing in the sensitivity list has no implication.
In example 8, sig1 is higher priority.
Independence of Edges
While we have used posedge for each of the signals, its not mandatory that all three edges have to match. Each of these edges are independent of each other. They specify the polarity of each signal with which they are associated. It is more important that the edge specification for a signal should match the condition within the if.
always @(posedge sig1 or negedge sig2 or posedge sig3) // example 9
if (sig1) …..
else if (!sig2) ……
- Asynchronous control signal: sig1 - because of first "if" condition
- Active High - if condition and "posedge" are agreeing with each other
- Asynchronous control signal: sig2 - because of second "if" condition
- Active Low - if condition and "negedge" are agreeing with each other
- Clock signals: sig3 - the remaining signal from the sensitivity list
- Rising edge triggered - from the sensitivity list
- And finally, sig1 has higher priority than sig2.