Question about testbench can not catch posedge clk

Hi, I am testing apb signals on eda-playground.

module fsm(clk, PSEL, PENABLE, reset, out1, out2);
  input  clk;
  input PSEL;
  input PENABLE;
  input reset;
  output out1;
  output out2;
  
  reg [2:0] state;
  reg [2:0] next_state;

  // State encodings
  parameter [2:0]
    IDLE    = 3'b001,
    STATE_1 = 3'b010,
    FINAL   = 3'b100;
    
  // State machine output
  assign out1 = (state == STATE_1);
  assign out2 = (state == FINAL);
  
  // State transitions
  always @(*) begin // (*) because this state being affect by all others signals 
		case (state)
			IDLE: begin 
				if (PSEL & ~PENABLE) begin
					next_state = STATE_1;
				end else begin
					next_state = IDLE;
				end
			end
			STATE_1: begin
				if (PSEL & PENABLE) begin
					next_state = FINAL;
				end else begin
					next_state = STATE_1;
				end
			end
			FINAL: begin
				next_state = IDLE;
			end
			default: begin
				next_state = IDLE;
			end
		endcase
	end

  always @(posedge clk or negedge reset) begin
    if(~reset) begin
    	state <= IDLE;
    end else begin
    	state <= next_state;
    end
  end
endmodule
module test;

  reg  clk, reset, PSEL, PENABLE;
  wire out1, out2;
  
  // Instantiate device under test
  fsm DUT(.clk(clk),
          .PSEL(PSEL),
          .PENABLE(PENABLE),
          .reset(reset),
          .out1(out1),
          .out2(out2));
  
  task toggle_clk;
    begin
      #10 clk = ~clk;
      #10 clk = ~clk;
    end
  endtask
  
  initial begin
    reset = 0;
    #10;
    @(posedge clk);
    reset = 1;
  end
  
  initial begin
    	PSEL = 0;
    	PENABLE = 0;
    	//
//     	#10;
//     	PSEL = 1;
//     	#20;
//     	PENABLE = 1;
//     	#20;
//     	PSEL = 0;
//     	PENABLE = 0;
    
      @(posedge clk);
          PSEL = 1;

      @(posedge clk);
          PENABLE = 1;

      @(posedge clk);
          PSEL = 0;
          PENABLE = 0;
  end
  
  initial begin
    clk = 0;
    
    $display("Initial out1: %0h, out2: %0h",
      out1, out2);

    toggle_clk;
    $display("IDLE out1: %0h, out2: %0h",
      out1, out2);
    
    toggle_clk;
    $display("STATE_1 out1: %0h, out2: %0h",
      out1, out2);

    toggle_clk;
    $display("FINAL out1: %0h, out2: %0h",
      out1, out2);

    toggle_clk;
    $display("FINAL out1: %0h, out2: %0h",
      out1, out2);
    
    toggle_clk;
    $display("IDLE out1: %0h, out2: %0h",
      out1, out2);
    
    #1000;
    $stop;
  end
  
  initial begin
    // Dump waves
    $dumpfile("dump.vcd");
    $dumpvars(1, test);
    $dumpvars(1, DUT);
  end
  
endmodule

My question is when I try to use @(posedge clk); then state and next_state is not running correctly.
I thought it is a proper way to test APB signal. I do not know why it is wrong.

  initial begin
    	PSEL = 0;
    	PENABLE = 0;
    
//     	#10;
//     	PSEL = 1;
//     	#20;
//     	PENABLE = 1;
//     	#20;
//     	PSEL = 0;
//     	PENABLE = 0;
    
      @(posedge clk);
          PSEL = 1;

      @(posedge clk);
          PENABLE = 1;

      @(posedge clk);
          PSEL = 0;
          PENABLE = 0;


But if I use timing to configure PSEL and PENABLE

  initial begin
    	PSEL = 0;
    	PENABLE = 0;
    
    	#10;
    	PSEL = 1;
    	#20;
    	PENABLE = 1;
    	#20;
    	PSEL = 0;
    	PENABLE = 0;
    
//       @(posedge clk);
//           PSEL = 1;

//       @(posedge clk);
//           PENABLE = 1;

//       @(posedge clk);
//           PSEL = 0;
//           PENABLE = 0;
  end
  

then I can get state signal running after next_state one cycle. That is correct, right?


In this example, I use cadence xcelium 23.09.
Can anybody explain why using @(posedge clk); is not correct? I hope it is not a tool related question. Thank you.

Use nonblocking assignments in your testbench when using @(posedge clk).

2 Likes

Thank you for your answer @dave_59.