Skip to content

Procedural Blocks

delays

  • delays are only allowed in procedural blocks (initial and always)

Inter assignment delays

  • execution of entire statement is delayed by specified time (#5 a = b; delays assignment of b to a by 5 time units)

Intra assignment delays

  • delays within an assignment statement (a = #5 b; assigns value of b to a after 5 time units, but right-hand side is evaluated immediately)

example of delays

module clock (
    output logic clk
);
    initial begin
        clk = 0;
        forever #5 clk = ~clk; // toggle clk every 5 time units
        // OR:
        // #5 ns;
        // clk = ~clk;
    end
endmodule

example questions of delays

suppose clk has a rising edge at time 10, what are the values of a and b at time 20?

module delay_question1(input logic clk);
    logic[31:0] a = 0;
    logic[31:0] b = 0;
    always @(posedge clk) begin
        #5 a = a + 2;
    end
    always @(posedge clk) begin
        #5 b = a + 3;
    end
endmodule

unpredictable RESULT, because the new value of b maybe evaluated before or after a is updated.

suppose clk has a rising edge at time 10, what are the values of a and b at time 36 ?

module delay_question1(input logic clk);
    logic[31:0] a = 0;
    logic[31:0] b = 0;
    always @(posedge clk) begin
        #5 a <= a + 2;
    end
    always @(posedge clk) begin
        #5 b <= a + 3;
    end
endmodule

10ns: a = 0, b = 0 (initial values)

15ns: a = 2, b = 3 (both assignments executed, b uses old value of a (non-blocking))

20ns: a = 2, b = 3

30ns: a = 2, b = 3 (this is the negative edge of clk, no change)

35ns: a = 4, b = 5 (both assignments executed, b uses old value of a (non-blocking))


Sensitivity List

always_comb

  • require purely combinational logic (=)
    • if there is any storage element (flip-flop, latch), it will cause an sv RTL coding error
    • for example, incomplete case
  • automatically infers sensitivity list, including functions
  • forbids ambigious netlist
    • for example, multiple drivers to the same net
  • executes at time 0, so the output has valid value at time 0

always_ff

  • require purely sequential logic (<=)
    • if there is any combinational logic, it will cause an sv RTL coding error
    • for example, missing else branch in if statement
  • gives warning if there is latch inferred

always_latch

  • when intended to infer latch

always@(*)

  • similar to always_comb, but may NOT infer complete sensitivity list when contains functions
  • and it does not automatically execute at time 0, but waits for an event in the sensitivity list
  • warning when latches are inferred (incomplete assignments in some branches if/case)

always block sensitivity list

  • single edge: always @(posedge clk) or always @(negedge rst_n)
  • multiple signals: always @(a or b or c) or always @(a, b, c)
  • all signals: always @(*) or always_comb (preferred for combinational logic)

    • always_comb automatically executes at time 0, and infer complete sensitivity list including functions
    • always@(*) may not infer a complete sensitivity list when contains functions.
  • CANNOT mix edge and level sensitivity in the same always block

  • always_ff @(posedge clk or posedge rst_n) for sequential logic with asynchronous reset
    • it stores values on clock edges

example of sensitivity list

module sensitivity_list (
    input logic clk,
    input logic rst_n,
    input logic a,
    input logic b,
    output logic y
); 
    // correct: single edge sensitivity
    always@(posedge clk) begin
        // sequential logic
    end
    // correct: multiple level sensitivity
    always@(a or b) begin
        // combinational logic
    end
    // correct: all signals sensitivity
    always@(*) begin
        // combinational logic
    end
    // incorrect: mixing edge and level sensitivity
    always @(posedge clk or a) begin
        // ERROR: cannot mix edge and level sensitivity
    end
endmodule

what this the synthesized hardware for q1 and q2?

module bad_FF_coding(
input logic clk, d, reset_n,
output logic q2);

logic q1;
always_ff@(posedge clk) begin
    if(!reset_n) // Reset only explicitly applied here
        q1<=1'b0; 
    else begin
        q1<=d;
        q2<=q1; // q2 is inferred here without explicit reset logic
    end
end
endmodule: bad_FF_coding

q1 is a flip-flop with asynchronous reset. q2 is a clock enable, not a simple flip-flop, because it does not have reset logic.

1765073648009

to fix this issue, we need to add reset logic for q2:

module good_FF_coding(
input logic clk, d, reset_n,
output logic q2);
logic q1;
always_ff@(posedge clk) begin
    if(!reset_n) begin // Reset applied to both q1 and q2
        q1<=1'b0; 
        q2<=1'b0;
    end
    else begin
        q1<=d;
        q2<=q1; 
    end
end
endmodule: good_FF_coding

or use two separate always_ff blocks:

module good_FF_coding(
input logic clk, d, reset_n,
output logic q2);
logic q1;
always_ff@(posedge clk or negedge reset_n) begin
    if(!reset_n) 
        q1<=1'b0; 
    else 
        q1<=d;
end
always_ff@(posedge clk or negedge reset_n) begin
    q2 <= q1; 
end
endmodule: good_FF_coding
module example3(
    input logic clk,
    input logic a,b,c,
    output logic f
);

    logic t; // the intermediate signal
    always_ff @(posedge clk) begin
        t <= a & b; // t is registered
        f <= t & c;
    end
endmodule: example3

for <= assignment, we use D-FF

the clk signal for both D-FF is the clk

a & b is combinational logic before the first D-FF, enters into the D input of the t D-ff

t & c is combinational logic before the second D-FF, enters into the D input of the f D-ff

1765074890472


non-synthesizable constructs

  • used for simulation only, not synthesizable

initial block

  • executes once at time 0, then terminates. not synthesizable in RTL
  • multiple initial blocks allowed in a module, executed in parallel