A previous article showed different examples of using an always block to implement combinational logic. An always block is also mainly used to implement sequential logic which has memory elements like flip flops that can hold values.

JK Flip Flop

A JK flip flop is one of the many types of flops used to store values and has two data inputs j and k along with one for reset rstn and another for clock clk . The truth table for a JK flop is shown below and is typically implemented using NAND gates.

rstnjkqComments
0000When reset is asserted, output is always zero
100Hold valueWhen both j and k are 0, output remains the same as before
1011When k=1, output becomes 1
1100When k=0, output becomes 0
111Toggle valueWhen j=1,k=1 output toggles current value

The behavioral Verilog code for a JK flip-flop can be written as shown below


module jk_ff ( input 			j, 				// Input J
               input 			k, 				// Input K
               input 			rstn, 		// Active-low async reset
               input 			clk, 			// Input clk
               output reg q); 			// Output Q

	always @ (posedge clk or negedge rstn) begin
		if (!rstn) begin
			q <= 0;
		end else begin
	  	q <= (j & ~q) | (~k & q);
	  end
  end
endmodule

Testbench

First declare all variables used in the testbench and start a clock using a simple always block that can be driven to the design. Then instantiate the design and connect its ports with corresponding testbench variables. Note that q is of type wire because it is connected to an output of the design which will be actively driving it. All other inputs to the design are of type reg so that they can be driven within a procedural block such as initial.

The stimulus first initializes all inputs to the design to zero and then de-asserts reset after some time. A for loop is used to drive different values to j and k which are driven at random times. Once the loop is done, wait for some more time and finish the simulation.


module tb;
	// Declare testbench variables
	reg j, k, rstn, clk;
	wire q;
	integer i;
	reg [2:0] dly;
	
	// Start the clock 
	always #10 clk = ~clk;
	
	// Instantiate the design
	jk_ff 	u0 (	.j(j), .k(k), .clk(clk), .rstn(rstn), .q(q));
	
	// Write the stimulus
	initial begin
		{j, k, rstn, clk} <= 0;
		#10 rstn <= 1;
		
		for (i = 0; i < 10; i = i+1) begin
			dly = $random;
			#(dly) j <= $random;
			#(dly) k <= $random;
		end
		
		#20 $finish;
	end
endmodule

Note from the simulation wave that at the posedge of clock, output q changes value based on the state of inputs j and k as given in the truth table.

Modulo-10 counter

Modulus(MOD) counters simply count upto a certain number before rolling back to zero. A MOD-N counter will count from 0 to N-1 and then roll back to zero and start counting again. Such counters typically require log2N number of flops to hold the count value. Shown below is the Verilog code for a MOD-10 counter that keeps counting up at every clock clk as long as reset rstn is deasserted.

Verilog parameters can be used to make a MOD-N counter which is more scalable.


module mod10_counter ( 	input		clk,
												input 	rstn,
												output	reg[3:0] out);
												
	always @ (posedge clk) begin
		if (!rstn) begin
			out <= 0;
		end else begin
			if (out == 10) 
				out <= 0;
			else
				out <= out + 1;
		end
	end
endmodule

Testbench

The testbench first declares some variables that can be assigned some values and driven to the design inputs. The counter module is then instantiated and connected with the testbench signals which are later driven with some values in the stimulus. Since the counter also requires a clock, the testbench clock is modeled with an always block. The stimulus simply sets default values at time 0ns, then deasserts reset after 10ns and the design is allowed to run for some time.


module tb;
	reg clk, rstn;
	reg [3:0] out;
	
	mod10_counter u0 ( .clk(clk), .rstn(rstn), .out(out));
	
	always #10 clk = ~clk;
	
	initial begin
		{clk, rstn} <= 0;
		
		#10 rstn <= 1;
		#450 $finish;
	end
endmodule

See that the counter module counts from zero to 9, rolls over to zero and starts counting again.

4bit Left Shift Register

Shown below is a 4-bit left shift register that accepts an input d into LSB and all other bits will be shifted left by 1. For example, if d equals zero and the initial value of the register is 0011, it will become 0110 at the next edge of the clock clk .


module lshift_4b_reg (  input d,                      
                        input clk,                    
                        input rstn,                   
                        output reg [3:0] out
                     );
 
   always @ (posedge clk) begin
      if (!rstn) begin
         out <= 0;
      end else begin
         out <= {out[2:0], d};
      end
   end
endmodule

Testbench

The testbench follows a similar template like the one shown before where some variables are declared, design module is instantiated and connected with the testbench signals. Then a clock is started and the stimulus is driven to the design using an initial block. In this testbench example, different values of d has to be exercised and hence a for loop is used to iterate 20 times and apply random values to the design.


module tb;
	reg clk, rstn, d;
	wire [3:0] out;
  integer i;
	
  lshift_4b_reg u0 (  .d(d), .clk(clk), .rstn(rstn), .out(out));
	
	always #10 clk = ~clk;
	
	initial begin
    {clk, rstn, d} <= 0;
    
    #10 rstn <= 1;
	
    for (i = 0; i < 20; i=i+1) begin
      @(posedge clk) d <= $random; 
    end
    
    #10 $finish;
	end  
endmodule

Note that each bit is shifted to the left by 1 and the new value of d is applied to LSB.