Synchronous Sequential Logic
2022-2024
Now that we know that computations propagates in combinational operators, and they are not instantaneous.
How to reliably have a sequence of computation where we reuse the same combinational operator?
Imagine that we want to compute the sum of a sequence of numbers by using a single adder. Each number has to be presented at the input of the adder, we have to maintain the inputs stable as long as the result is not valid at the output. Once the output is valid, we have to store the result before new computations starts propagating.
When we present new values at the inputs of a combinational bloc, we have to wait for the inputs to be steady, then we have to wait for the propagation delay to have a valid output.
Also, this output is only valid as long as the input values do not change. If one of the inputs value change, we have to wait again for the output to be steady.
NOTE: If input value change, the output can will not change instantaneously. The minimum time for the output change after inputs change is called contamination time. Nevertheless, the output is not valid until the propagation is complete.
One first thing that we want to ensure, is that the inputs values do not change until the propagation is complete.
We will use a memorizing element to capture the inputs and guarantee that they do not change before the end of the propagation.
We will thus, sample the inputs at the same moment and wait for a time longer than the longest propagation time before sampling new values.
Here we can see that we have valid output values, but we do not know exactly when if we just observe the output.
What we can do here, is to sample the output value when we sample new inputs. Thus, we have the guarantee that the sampled output will not change until the next computation phase.
Finally, as we need to sample inputs and outputs at the same moment we will use the same global signal to guarantee that sampling occurs in a synchronous manner.
We have obtained a complete synchronous operator where the inputs and outputs are synchronized and where the outputs can also be easily used as the inputs of other combinational blocks.
This global signal is called a clock (often named clk
).
Generally this signal has to be periodic square wave and the sampling
happens at each rising (or falling) edge (when it goes from 0 to 1). We
will see later why, when we will study the construction of
flip-flops.
The memorizing element ;-)
clk | D | Q |
---|---|---|
\uparrow | 0 | 0 |
\uparrow | 1 | 1 |
\downarrow | x | Q ^{-1} |
0 | x | Q ^{-1} |
1 | x | Q ^{-1} |
The D Flip-Flop is the main memorizing element for synchronous logic.
For each rising edge of the clock, the value of it’s input D if captured, otherwise, the value of the output is memorized and do not change.
All the outputs of flip-flops are synchronous and can only change at a clock edges.
Thus, the output of a flip-flop is always a delayed version of its input. Also, all changes that could appear on the inputs between two consecutive clock edges will be filtered.
With synchronous logic, changes can only happen at discrete times that correspond to the clock edges.
Memory
To maintain a logical level, we can use a couple of inverters connected in loop.
This will form a bi-stable element with two stable states. The looped inverters ensure that the electrical level at the output is maintained to a correct value.
Using CMOS technology, this is the smallest memorizing element and is the base of what is called an sram memory point.
It is not a practical to use that design because there are no inputs to control or change the value of its output. But, the important thing to keep in mind here is that we have a combinational loop with the identity boolean open loop function (we could have used a single buffer instead of two inverters).
Next, we will see how we can construct a controllable memorizing element.
The D Latch
In principle, it is similar to having a looped multiplexor.
ena | D | Q | |
---|---|---|---|
0 | x | Q ^{-1} | closed |
1 | 0 | 0 | transparent |
1 | 1 | 1 | transparent |
The D Latch has two states:
ena
signal is high and
its output D
is connected directly to its output
Q
.Q
keeps its value
(memorizing state).A D Latch is also called a level sensitive latch.
NOTE that this construction is purely theoretical, if we go don to the CMOS transistor structure, a D Latch is generally built differently.
The D Flip-Flop
The edge sensitive memorizing element.
We can construct a Flip-Flop with two level sensitive latches. The first one is called the Master while the second is the Slave. The two latches are connected to complementary control signals:
the master with the inverted input clock,
the slave with the clock.
When the input clock is low, the Master is transparent and the internal signal (connecting the two latches) is a copy of the input D, while the output keeps its previous value.
When the input clock is high, the Master memorizes the value of the internal signal and, as the Slave is transparent and outputs its value.
This behaviour allows capturing the value that we have at the input at the moment when the clock goes from low to high. We have built an edge-sensitive memorizing element.
NOTE that, here also, this construction is purely theoretical, and optimized, transistor level structures are used in real designs.
A register is a bank of D-FF in parallel that share the same clock input. It can be represented with the same symbol as a D-FF, exception the fact that inputs and outputs are multi-bit buses.
In the previous figure we show a 4-bit register.
Note that often, we will use the term register even for D-FF (1-bit register).
For a D flip-flop to behave correctly the input must be stable around the rising edge of the clock. Otherwise, the sampled value may be incorrect.
Thus, there is a temporal window around the rising edge of the clock that is defined:
Additionally, t{co} (clock-to-output) represents the delay between the rising edge of the clock and a valid output. It can be seen as the propagation delay of the D-FF. By design, t_{co} is larger than t_h, which allows connecting the output of a D-FF directly to the input of another D-FF.
Critical Path in synchronous logic
Minimal clock period:
T \geq T_{min} = t_{co} + t_{crit} + t_{su}
Or maximum frequency:
F \leq F_{max} = \frac{1}{t_{co} + t_{crit} + t_{su}}
In the context of synchronous logic, the critical path is the longest combinational path between two synchronisation points (registers or flip-flops) in all the system.
This critical path has a direct impact on the maximum frequency of the system’s clock. Thus, the complexity of the combinational logic will have an impact on the maximum working frequency of a synchronous system.
NOTE Here we have assumed that the clock arrives simultaneously to all the registers of a circuit. In a real design, some variation can appear, due to the propagation of the clock signal, between the moments when the clock reaches each register. This delay variation is called clock skew and should be considered for accurate timing validation.
module dff( input clk,
input d,
output logic q);
always_ff @(posedge clk)
q <= d;
endmodule
module reg4( input clk,
input [3:0] d,
output logic[3:0] q);
always_ff @(posedge clk)
q <= d;
endmodule
To describe synchronous logic we use a process declared with the
always_ff
keyword. The process is executed when
ever we have a rising edge of the clock (posedge
keyword).
@(xxxx)
represents what is called the sensitivity list
of the process.
Note also that the assignment operator (<=
) is
different from what we have seen for combinational logic. This is called
non blocking assignment operator. It guarantees that, when
simulating SystemVerilog code, the left side of the assignments do not
change until all the process sensitive to the same event (the
clock rising edge, for example) are executed.
module shift_reg(
input clk,
input i,
output q);
logic q0,q1,q2,q3;
always_ff @(posedge clk)
begin
q0 <= i;
q1 <= q0;
q2 <= q1;
q3 <= q2;end
assign q = q3;
endmodule
In a shift register, flip-flops are chained such as the output of each flip-flop is connected directly to the input of the following flip-flop.
The output of the shift-register (the output of the final flip-flop) is a delayed version of the input. The total delay is proportional to the number of flip-flops.
Note also that each flip-flop output represent a different delayed version of the input.
Due to the usage of the delayed assignment operator, these assignments:
begin
q0 <= i;
q1 <= q0;
q2 <= q1;
q3 <= q2;end
are executed in parallel.
Thus, the order of the assignment is not important ans it is equivalent to write:
begin
q3 <= q2;
q2 <= q1;
q1 <= q0;
q0 <= i;end
To describe in a compact manner, we could have used the concatenation operator as shown in the following example:
module shift_reg( input clk,
input i,
output q );
logic [3:0] q_r;
always_ff @(posedge clk)
2:0],i};
q_r <= {q_r[
assign q = q_r[3];
endmodule
module dff( input clk,
input ena,
input d,
output logic q);
always_ff @(posedge clk)
if(ena)
q <= d;
endmodule
We are here combining combinational logic and a synchronous flip-flop. The intermediary signal between the multiplexor and the flip-flop is implicit in the code. Another descriptions could be:
module dff( input clk,
input ena,
input d,
output logic q);
wire q_next;
assign q_next = ena? d : q;
always_ff @(posedge clk)
q <= q_next;
endmodule
Or using a process for the combinational logic:
module dff( input clk,
input ena,
input d,
output logic q);
logic q_next;
always_comb
if(ena)
q_next = d;else
q_next = q;
always_ff @(posedge clk)
q <= q_next;
endmodule
Note that for combinational logic, the
if...else
statement must be complete we must explicitly
express all cases, whereas, when just expressing synchronous logic, if a
case is missing, it means that the signal keeps its value
(memorize) which is legal.
always_ff @(posedge clk)
if(ena)
q <= d;// else
// q <= q; // implicit
Example of a 4-bit counter:
module dff( input clk,
output logic[3:0] q);
always_ff @(posedge clk)
1;
q <= q +
endmodule
This is modulo 16 counter. It will count through all the values between 0 and 15.
Here also we are combining combinational logic with registers.
Note that:
q+1
),
q
represents the actual value of the register,q
represents
its value after the clock edge.In other words, the next value of the register (q+1
)
will replace its actual value (q
) at the rising edge of the
clock.
Another way to express the same behaviour would be:
module dff( input clk,
output logic[3:0] q);
wire [3:0] q_next;
assign q_next = q + 1;
always_ff @(posedge clk)
q <= q_next;
endmodule
Note also that with this counter we do not control the initial value of the register at power up. Indeed, when powering up a flip-flop we can not predict its value. We need an additional mechanism to force its initial state.
How to force the initial value of a register?
module dff( input clk,
input rst,
input [3:0] d,
output logic[3:0] q);
always_ff @(posedge clk)
if(rst)
0;
q <= 'else
q <= d;
endmodule
A synchronous reset allows forcing the state of a register. It is called synchronous because its effect will only appear at rising edge after it is active.
It can be seen as an additional combinational function that forces the next value of the register input to its initial value. Nevertheless, it is possible that this reset is implemented at the transistor level for optimized implementations.
Another way to represent this is:
module dff( input clk,
input rst,
input [3:0] d,
output logic[3:0] q);
wire [3:0] q_next;
assign q_next = rst? '0 : d;
always_ff @(posedge clk)
q <= q_next;
endmodule
Notes:
n
, to
express the negation.For example:
module dff( input clk,
input nrst,
input [3:0] d,
output logic[3:0] q);
always_ff @(posedge clk)
if(!nrst)
0;
q <= 'else
q <= d;
endmodule
if...else
statement.module dff( input clk,
input nrst,
input [3:0] d,
output logic[3:0] q);
always_ff @(posedge clk or negedge nrst)
if(!nrst)
0;
q <= 'else
q <= d;
endmodule
Contrary to the synchronous reset, an asynchronous reset will have an immediate effect. The way to express this in SystemVerilog, is to add a second event to the sensitivity list of the process. In the previous example, we have an active low reset signal, thus, if it goes from 1 to 0, the process is triggered and the register is initialized.
Warning registers have a unique clock signal, thus, even if there is a second event in the sensitivity list, the second signal can not be interpreted as clock.
It is even clearer with the following example of an active high asynchronous reset:
module dff( input clk,
input rst,
input [3:0] d,
output logic[3:0] q);
always_ff @(posedge clk or posedge rst)
if(rst) begin
// asynchronous reset
0;
q <= 'end
else begin
// synchronous behaviour
q <= d;end
endmodule
Notes
Asynchronous reset can only be implemented at the transistor level.
Asynchronous reset is generally used as a global reset signal that can initialize all the registers of a circuit.
propose a structure to memorise the 4 last samples,
propose a structure to compute the sum of these four values combinationally,
deduce a structure to compute the average of those values.
write the SystemVerilog code for the proposed structure.
© Copyright 2022-2024, Tarik Graba, Télécom Paris. | |
Le contenu de cette page est mis à disposition selon les termes de la licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International. | |
The content of this page is licensed under a Creative Commons Attribution-ShareAlike 4.0 International Licence. |