Digital System Design
Sequential Logic Modeling and Synthesis
Nitin Chandrachoodan
IIT Madras
Sequential Logic
Modeling
From Combinational to Sequential
Combinational
● Output depends only on current inputs
● AND, OR, NOT etc.
From Combinational to Sequential
Combinational Sequential
● Output depends only on current inputs ● Output depends on current inputs and
● AND, OR, NOT etc. HISTORY
● Flip-flops, latches, memory
State or Memory: perform computations based
on past values or stored values
Clock
● ‘Heartbeat’ signal
● Ensure synchronization of operations
○ Control precise time when a value changes
Clocks in HDL
● Basic clock idea very simple
● Multiple clocks, domains, synchronization etc. follow later
● Clock distribution etc. highly complex problems
Clock Edges
● Design Convention: positive
edge unless specified otherwise
● Actual details of edge:
○ rise time
○ fall time
○ slope
○ leakage currents etc.
○ ignore these for now
Coding in Verilog
// Traditional style
always @(posedge clk) begin
q <= d;
end
Coding in Verilog
// Traditional style
always @(posedge clk) begin
q <= d;
end
// Modern style (preferred)
always_ff @( posedge clk) begin
q <= d;
end
Coding in Verilog
// Traditional style ● always_ff is modern Verilog
always @(posedge clk) begin syntax
q <= d; ● Clock edge in sensitivity list
end ● Non-blocking assignment (<=)
required
// Modern style (preferred)
always_ff @( posedge clk) begin
q <= d;
end
module basic_dff(
D-flip-flop in Verilog
input wire clk, // Clock input
input wire d, // Data input
output reg q // Output
);
always_ff @(posedge clk) begin
q <= d;
end
endmodule
module counter_2bit(
input wire clk,
Simple Counter output reg [1:0] count
);
always_ff @(posedge clk) begin
count <= count + 1'b1;
end
endmodule
Flip-Flops and
Registers
Coding D-FF in Verilog
module dff_simple(
input wire q, z,
output reg clk
);
// Basic D flip-flop
always_ff @( posedge z)
clk <= q;
endmodule
Coding D-FF in Verilog
module dff_simple( ● Simple pattern match
● Names do not matter
input wire q, z,
● Prefer always_ff
output reg clk ● Convention to map this to D-FF
); ● Power-on value?
// Basic D flip-flop
always_ff @( posedge z)
clk <= q;
endmodule
Power-on - Reset
module dff_reset( ● Asynchronous reset
input wire clk, rst_n, d, ● Reset condition takes priority
output reg q ○ Code is a “model” ofHardware
);
// D flip-flop with async reset
always_ff @(posedge clk or negedge rst_n)
if (!rst_n)
q <= 1'b0;
else
q <= d;
endmodule
Power-on - Reset
module dff_reset( ● Synchronous reset
input wire clk, rst_n, d, ● Reset waits for clock
output reg q
);
FPGAs often use sync reset
// D flip-flop with sync reset
always_ff @(posedge clk)
if (!rst_n)
q <= 1'b0;
else
q <= d;
endmodule
Multi-bit Register
module register #( ● Multiple bits controlled by same clock,
parameter WIDTH = 8 reset
)( ● Treated as single logical value
input wire clk, rst_n, ● Usually for numbers, buses
input wire [WIDTH-1:0] d, ● Parameterized definition
output reg [WIDTH- 1:0] q ○ Can override when instantiating
○ Reusable code
);
always_ff @( posedge clk)
if (!rst_n)
● Note: Replication operator in Verilog
q <= {WIDTH{ 1'b0}};
else
q <= d;
endmodule
Shift Register
module shift_reg(
input wire clk, rst_n,
input wire data_in,
output reg [3:0] q
);
always_ff @(posedge clk)
if (!rst_n)
q <= 4'b0;
else
q <= {q[2:0], data_in};
endmodule
Loadable Shift Register
module shift_reg_loadable #( ● Priority of inputs
parameter WIDTH = 4
● Multiple operations
)(
○ Reset > Load > Shift
input wire clk, rst_n,
● Translate into appropriate hardware
input wire shift_en, load,
input wire data_in,
input wire [WIDTH-1:0] parallel_in,
output reg [WIDTH-1:0] q
);
always_ff @(posedge clk)
if (!rst_n)
q <= {WIDTH{1'b0}};
else if (load)
q <= parallel_in;
else if (shift_en)
q <= {q[WIDTH-2:0], data_in};
endmodule
Test Bench for Sequential Circuit
module tb_shift_reg ; . . .
reg clk, rst_n, data_in;
wire [3:0] q; // Test sequence
initial begin
shift_reg dut(.*); rst_n = 0; data_in = 0;
#10 rst_n = 1;
#10 data_in = 1; // Shift in 1
// Clock generation
#10 data_in = 1; // Shift in 1
initial begin
#10 data_in = 0; // Shift in 0
clk = 0;
#10 data_in = 1; // Shift in 1
forever #5 clk = ~clk; #10 $finish;
end end
endmodule
. . .
Demo
Synthesis and
RTL
Synthesis and RTL
● RTL = Register Transfer Level
● Describes digital circuit in terms of:
○ Registers (storage elements)
○ Data transfers between registers
○ Logic operations on data
● Focus is on data flow, not individual gates
● Represents synchronous digital design where operations happen on clock
edges
Verilog Code Styles
// Not RTL - behavioral, may not synthesize
always @(a or b) begin
#2 y = a + b; // Delays
for(i=0; i<8; i=i+1) begin // Loop
z[i] = y * 2; // Complex operation
end
end
Verilog Code Styles
// Not RTL - behavioral, may not synthesize // RTL - clear register transfer
always @(a or b) begin always_ff @(posedge clk) begin
#2 y = a + b; // Delays // Clear data path
for(i=0; i<8; i=i+1) begin // Loop result_reg <= a_reg + b_reg;
z[i] = y * 2; // Complex operation end
end
end
General RTL structure
// Combinational computation ● Registers hold values / storage / memory
assign result = a_reg + b_reg; ● Combinational logic performs
computations
// Synchronous Register Update ● RTL computes on stored values and
always_ff @( posedge clk) begin updates them
sum_reg <= result; // Register
end
RTL Synthesis Flow
Convert RTL to gate-level netlist: Primary outputs of Synthesis:
● Parse HDL and create internal ● Gate-level netlist
representation ● Resource utilization report
● Identify registers and combinational logic ● Warning/error messages
● Optimize logic
● Map to target technology
Garbage-in Garbage-out: good RTL coding
practices lead to good synthesized netlists and
vice versa
Coding for
Synthesis
General Principles
● Write code that clearly represents hardware structure
● Maintain consistent coding style throughout the design
● Use synchronous design practices wherever possible
● Explicitly declare all inputs and outputs
● Follow hierarchical design principles
Know what hardware you want, and write the code to get it.
Not the other way around!
Recommended Practices
● Use parameters instead of hard-coded values
● Implement one function per module
● Keep combinational and sequential logic separate
● Use named port connections for clarity
● Document assumptions and design constraints
Common Non-Synthesizable Constructs
● Time-Related Constructs
○ Initial blocks (except for testbenches)
○ Delay specifications (#)
○ Wait statements
○ Fork-join constructs
● File Operations
○ $readmemh/$readmemb (synthesis-dependent)
○ $display, $monitor
○ File I/O operations
● Variable Types
○ Real or shortreal
○ Time
○ Event data types
Unwanted Latches
// BAD - creates latch // BAD - creates latch
always @(*) begin case (sel)
if (sel) out = a; 2'b00: out = a;
end 2'b01: out = b;
endcase
// GOOD - no latch
always @(*) begin // GOOD - no latch
out = 'b0; // Default assignment case (sel)
if (sel) out = a; 2'b00: out = a;
end 2'b01: out = b;
default: out = 'b0;
endcase
Unwanted Latches
// BAD - creates latch // BAD - creates latch
always @(*) begin case (sel)
if (sel) out = a; 2'b00: out = a;
end 2'b01: out = b;
endcase
// GOOD - no latch
always @(*) begin // GOOD - no latch
out = 'b0; // Default assignment case (sel)
if (sel) out = a; 2'b00: out = a;
end 2'b01: out = b;
default: out = 'b0;
endcase
Best practices:
● Always provide default assignments
● Use complete case statements with default
● Initialize all variables in combinational blocks
● Use 'case' instead of 'casex' or 'casez'
Register Inference
// Recommended synchronous register Key Guidelines
always @(posedge clk) begin
1. Use non-blocking assignments (<=) for
if (rst) begin
sequential logic
q <= 'b0;
end else begin 2. Use blocking assignments (=) for
q <= d; combinational logic
end
3. Avoid mixing blocking and non-blocking
end
assignments
4. Keep reset logic synchronous when possible
Common Register Patterns
// Enable flip-flop // Shift register
always @(posedge clk) begin always @(posedge clk) begin
if (rst) begin if (rst) begin
q <= 'b0; shift_reg <= 'b0;
end else if (en) begin end else begin
q <= d; shift_reg <= {shift_reg[ 6:0],
end data_in};
end end
end
Sync vs. Async reset
Asynchronous reset Synchronous reset
● No waiting for clock ● Easier timing analysis
● Critical for power-on scenarios where ● Better for high speed designs (no async paths)
clock may not be stable (PLL locking) ● Cleaner designs (?)
Cons: Cons
● Timing tree harder to analyze ● Clock must be stable first
● Can cause metastability ● May use extra logic (MUXes etc.)
● Requires separate routing resources ● Reset release takes extra cycle
Still generally preferred at module level in FPGAs
Synthesis Examples - delays in Verilog
// Non-synthesizable // Synthesizable
always @(posedge clk) begin always @(posedge clk) begin
#2 a = b; a <= b;
#3 c = d; c <= d;
end end
Synthesis Examples - initial blocks
// Non-synthesizable // Synthesizable
initial begin always @(posedge clk) begin
counter = 0; if (rst) begin
state = IDLE; counter <= 0;
end state <= IDLE;
end else begin
// Normal operation
end
end
Synthesis Mistakes - Multiple drivers
// BAD - Multiple drivers // GOOD - Single driver
always @(*) begin always @(*) begin
out = in1; if (sel)
end out = in1;
always @(*) begin else
out = in2; out = in2;
end end
Synthesis Mistakes - Incomplete Sensitivity Lists
// BAD - Missing signals // GOOD - Complete sensitivity
always @(a) begin always @(*) begin
// b changes won't trigger out = a + b;
out = a + b; end
end
Synthesis Mistakes - Mixing Assignment Types
// BAD - Mixing assignments // GOOD - Consistent assignments
always @(posedge clk) begin always @(posedge clk) begin
temp = a + b; // Blocking q <= a + b; // Single
q <= temp; // Non-blocking non-blocking
end end
Synthesis Mistakes - Complex Combinational Logic
// BAD - Too complex // GOOD - Split into smaller blocks
always @(*) begin always @(*) begin
case (state) next_state = state;
// ... many states with case (state)
// complex logic // ... state transitions only
endcase endcase
end end
always @(*) begin
// ... output logic
end
Key Points
● Synthesizable code is a subset of Verilog -
○ not all Verilog translates to hardware
● No substitute for designing in abstraction
○ First design at block level
○ Then write code
● Pattern matching
○ Understand how patterns get compiled to gates for best efficiency
Timing … is everything…
Physical World Limitations
● Gates are made of transistors, and connected by wires
○ Voltages cannot switch instantaneously - capacitance
○ Resistance causes power dissipation
○ Gates have “propagation delay”
■ Idealized as simple delay between input and output
● Digital signals have “rise time”, “fall time”
○ Sometimes ignored
● Flip-flops have
○ “setup”, “hold” constraints
○ “propagation delay” - clock-to-q delay
Setup and Hold Time
Setup Time (Ts) Hold Time (Th)
● Minimum time before clock edge that data ● Minimum time after clock edge that data
must be stable must remain stable
● Ensures data is captured correctly by the ● Prevents data from changing too quickly
flip-flop after clock edge
● Data must remain unchanged during ● Usually smaller than setup time
setup window ○ can be controlled through layout
● Violation can lead to metastability ● Critical for reliable operation
Setup and Hold Time
Setup Time (Ts) Hold Time (Th)
● Minimum time before clock edge that data ● Minimum time after clock edge that data
must be stable must remain stable
● Ensures data is captured correctly by the ● Prevents data from changing too quickly
flip-flop after clock edge
● Data must remain unchanged during ● Usually smaller than setup time
setup window ○ can be controlled through layout
● Violation can lead to metastability ● Critical for reliable operation
Can usually be fixed by Must be fixed at design
slowing clock time!
Metastability
● What is Metastability?
○ Unstable state between valid logic levels
○ Output oscillates before settling to valid state
○ Can occur when setup/hold times are violated
Requires more detailed
● Causes and Effects understanding of circuit
○ Data changing during setup/hold window
○ Input signals too close to clock edge level behaviour.
○ Crossing clock domains
○ Can propagate through multiple stages Bottom Line: do not violate
● Handling Metastability setup or hold time
○ Using synchronizers
○ Adding pipeline stages
○ Proper timing constraints
○ Clock domain crossing techniques
Clock to Q (output) delay
● Basic Concepts
○ Time from clock edge to output change
○ Always present in sequential elements
○ Varies with:
■ Process variations
■ Temperature
■ Voltage
■ Loading conditions
● Impact on Design
○ Affects maximum operating frequency
○ Part of critical path timing
○ Must be considered in timing calculations
○ Can vary between flip-flops
Capture Window Timings
Critical Path
Definition Identifying Critical Paths
● Longest combinational path between ● Between sequential elements
registers ● Through complex logic
● Determines maximum operating ● Often in:
frequency ○ Arithmetic units
● Includes: ○ Control logic
○ Clock-to-Q delay ○ Deep logic paths
○ Logic delays
○ Routing delays
○ Setup time
Critical Path
Frequency Calculation
Sequential Test
Benches
Clock Generation
module testbench ;
reg clk = 0;
// Method 1: Simple toggle
always #5 clk = ~clk; // 100MHz clock
// Method 2: Initial block with forever
initial begin
clk = 0;
forever #5 clk = ~clk;
end
endmodule
Reset Sequencing
initial begin
Key Points:
// Initialize signals
rst_n = 1'b0;
● Hold reset for multiple cycles to ensure
data_in = 8'h00;
proper initialization
// Hold reset for several clock cycles
● Wait a few cycles after reset before
repeat(5) @(posedge clk); starting tests
● Keep stimulus aligned to clock edges
// Release reset and wait a couple cycles
rst_n = 1'b1;
repeat(2) @(posedge clk);
This is a model, try to get it close to reality, but
// Begin test sequence
understand limitations
data_in = 8'hAA;
end
Using task in test sequences
// Task for data write sequence // Usage in test
task write_data; initial begin
input [7:0] data; // Wait for reset to complete
begin wait(rst_n);
@( posedge clk);
write_data( 8'hAA);
data_in = data;
write_data( 8'hBB);
valid = 1'b1;
end
@( posedge clk);
valid = 1'b0; ● Improves readability
end ● Allows complex timing (wait for clocks,
endtask valid, other events)
● Reusable
Using function in test sequences
// Function to check output validity // Usage in test
function automatic bit check_output; always @(posedge clk) begin
input [7:0] actual, expected; if (!check_output(data_out, expected_data))
begin error_count++;
if (actual !== expected) begin end
$display("Error: Exp %h, Got %h",
expected, actual); ● Modular verification
return 0;
● Reusable (similar to task)
end
● No notion of time
return 1;
● Error counts etc: useful pattern
end
endfunction