Sequential Verilog

Al Wood

Registers

A simple memory to hold state, normally implemented as D-type flip-flop.

reg  y;
reg [1:0] a2, b2;

Inputs and outputs can be declared as registers:

module mymod (
   input reg [1:0] y2;
   output reg [2:0] y3;

By convention usually only outputs are registers and inputs are wires.

Example: Decoder with register

module decoder (
   input  [1:0]     a,
   input            en,
   output reg [3:0] y
  )

   always_comb
      casex ({en,a})
         3'b0xx: y = 4'b0000;
         3'b100: y = 4'b0001;
         3'b101: y = 4'b0010;
         3'b110: y = 4'b0100;
         3'b111: y = 4'b1000;
      endcase    // {en,a}

endmodule

Sequential always blocks

always @(posedge clk)
   a <= b;

At the next positive edge of the clock, register a will acquire the value held in b (which could be a register or wire).

SystemVerilog provides:

always_ff @(posedge clk)
   a <= b;

Delayed (non-blocking) assignments

<= causes the value to be transferred on the next clock edge. It should only be used in sequential always blocks.

Conversely = (aka blocking assignment) happens immediately and should only be used in combinatorial always blocks.

This means you can do surprising things with registers:

always_ff @(posedge clk)
   begin
      a <= b;
      b <= a;
   end

Common problems

You now know Verilog :-) Here are the common “gotchas”.

  • Variable assigned in multiple always blocks
  • Incomplete branch or output assignment
always_comb
   if (a > b)
      gt = 1'b1; // no eq assignment in branch
   else if (a == b)
      eq = 1'b1; // no gt assignment in branch
  // final else branch omitted

According to Verilog definition gt and eq keep their previous values when not assigned which implies internal state, unintended latches are inferred.

Fixing incomplete output assignment (1)

These sort of issues cause endless hair pulling avoid such things. Here is how we could correct this:

always_comb
   if (a > b) begin
      gt = 1'b1;
      eq = 1'b0;
   end
   else if (a == b) begin
      gt = 1'b0;
      eq = 1'b1;
   end
   else begin
      gt = 1'b0;
      eq = 1'b0;
   end

Fixing incomplete output assignment (2)

Or we can use default values.

always_comb
   begin
      gt = 1'b0;
      eq = 1'b0;
      if (a > b)
         gt = 1'b1;
      else if (a==b)
         eq = 1'b1;
   end

Incomplete output with case statements (1)

Similar problems can occur with case statements:

always_comb
   case (a)
      2'b00: y = 1'b1;
      2'b10: y = 1'b0;
      2'b11: y = 1'b1;
   endcase

Incomplete output with case statements (2)

A default clause is a good catchall.

always_comb
   case (a)
      2'b00:    y =1'b1;
      2'b10:    y =1'b0;
      2'b11:    y =1'b1;
      default : y = 1'b1;
   endcase

Exercise 4

Which is actually lots of exercises, all in basic_verilog

  • blink: Make the LED flash. Extend to make LED’s flash in a pattern.
  • fibonacci: Count through the LEDs in a fibonacci sequence.
  • button: Make the LED’s count when you press the button. Why won’t it count nice and smoothly?
  • button_edge_detect: This solves the problem of detecting a button press.
  • lock: Unlock the device with a password. This leads into the next talk.