Search code examples
verilogsystem-verilogsequentialflip-flop

SystemVerilog Sequential Circuits Coding Style


I am currently working through Pong Chu's FPGA Prototyping By System Verilog Examples, specifically on Chapter 4 which covers sequential circuits. In it, Chu describes the method where a sequential circuit has the sequential part and the combinational part. So far so good. As an example, he shows how a DFF with synchronous clear is coded up:

module d_ff_sync_clr_2seg
   (
    input  logic clk,
    input  logic syn_clr,
    input  logic d,
    output logic q
   );

   // signal declaration
   logic r_reg, r_next;

   // body
   // D FF
   always_ff @(posedge clk)
      r_reg <= r_next;

   // next-state logic
   always_comb
      if (syn_clr)
         r_next = 1'b0;
      else
         r_next = d;

   // output logic
   assign q = r_reg;
endmodule

In the discussion, he states the syn_clr signal is only checked at the rising edge of the clock. He also provides a different formatting style for the same circuit which I found clearer:

module d_ff_sync_clr_1seg
   (
    input  logic clk,
    input  logic syn_clr,
    input  logic d,
    output logic q
   );

   // body
   always_ff @(posedge clk)
      if (syn_clr)
         q <= 1'b0;
      else
         q <= d;
endmodule

In the second example (d_ff_sync_clr_1seg), I can clearly see that yes, at the rising edge of the clock the always_ff block is activated and syn_clr is indeed sampled.

In the first (d_ff_sync_clr_2seg), longer example, the statement Chu makes that syn_clr is only checked at the rising edge of the clock isn't as clear. My thinking is that when syn_clr changes, the always_comb block is activated, and r_next is updated to be either 1'b0 or d. Then, at the rising edge of the clock, r_reg gets assigned the value of r_next, as it was set in the always_comb block. So indirectly it seems, syn_clr (or the results of checking syn_clr) is sampled at the rising edge of the clock. I don't see the connection between what is going on in the always_ff block which is just sensitive to the rising edge of the clock and the always_comb which will activate whenever syn_clr changes. How is syn_clr just sampled in at the rising edge of the clock, and hence is synchronous, if its in the always_comb block.

I understand that in an always_ff block the assignments are non-blocking and happen at the end of the block, but in this example there's only one assignment so OK.

At this point in the book Chu has mentioned FSMs and FSMDs but hasn't formally introduced those concepts in this chapter.

Perhaps I'm missing something else or my understanding of always blocks isn't as firm as I thought. Any clarification would be appreciated.


Solution

  • the statement Chu makes that syn_clr is only checked at the rising edge of the clock isn't as clear.

    You are correct. That statement is imprecise. r_next is sampled at the posedge of clk, not syn_clr.

    The 2nd code example is the proper way to model a simple DFF with synchronous clear.

    It is not clear why the author chose to show the 1st example at all.

    My thinking is that when syn_clr changes, the always_comb block is activated

    This is true, but the block is also activated when d changes. More generally, the block is triggered on any change of any signal on the RHS of an assignment (that does not also appear on the LHS) within the block.