0
\$\begingroup\$

I have mostly worked on VHDL and I have recently started learning Verilog.

I wrote a Moore Finite State Machine (FSM). The FSM is not resetting properly as current state upon reset doesn't go into initial state as indicated by its value cstat = xx by simulator at t=0. Also the output which depends upon cstate is also shown as oup1 = x.

The design and testbench is on EDA playground (https://www.edaplayground.com/x/5Uwi). With Cadence Incisive 15.20 simulator invoked with command line options

-timescale 1ms/1us -sysv -disable_sem2009

I get following log output showing the simulation failed:

[2020-03-09 15:12:36 EDT] irun -Q -unbuffered '-timescale' '1ms/1us' '-sysv' '-disable_sem2009' '-access' '+rw' design.sv testbench.sv  
irun: 15.20-s038: (c) Copyright 1995-2017 Cadence Design Systems, Inc.
    Top level design units:
        moore_fsm_tb
Loading snapshot worklib.moore_fsm_tb:sv .................... Done
ncsim> source /incisiv/15.20/tools/inca/files/ncsimrc
ncsim> run
FAILED
Time=0, rst=0, inp1=0, inp2=0, current state = xx, next state = 00, oup1 = x
Expected current state = 00, next state = 00, oup1 = 0
Simulation complete via $finish(1) at time 0 FS + 4
./testbench.sv:70       $finish;
ncsim> exit
Done

Design

module moore_fsm_top ( input wire clk,
                   input wire rst,
                   input wire inp1,
                   input wire inp2,
                   output reg oup1,
                   output reg [1:0] cstat,
                   output reg [1:0] nstat
                  );


  localparam  MAX = 4000;
  reg [11:0] ccnt;
  reg [11:0] ncnt;
  wire maxedout;

  localparam  INP_X = 1'b0;
  localparam  INP_Y = 1'b1; 
  localparam  OUP_X = 1'b0;
  localparam  OUP_Y = 1'b1;

  localparam  UU = 2'b00;
  localparam  VV = 2'b01;
  localparam  WW = 2'b10;
  localparam  XX = 2'b11;

  always @ ( posedge clk, posedge rst ) begin
    if ( rst ) begin
      cstat <= UU;
    end else begin
      cstat <= nstat;
    end
  end

  always @ ( posedge clk, posedge rst ) begin
    if ( rst ) begin
      ccnt <= 12'b0;
    end else begin
      ccnt <= ncnt;
    end
  end

  always @ ( * ) begin
      case (cstat)
        UU, WW: ncnt = 12'b0;
        VV, XX: begin
          if (ccnt == (MAX-1)) begin
            ncnt = 12'b0;
          end else begin
            ncnt = ccnt+1;
          end
        end
    endcase
  end

  assign maxedout = (ccnt == (MAX-1)) ? 1'b1 : 1'b0;

  always @ ( * ) begin
    case (cstat)
      UU: begin
        nstat = UU;
        if (inp1 == INP_X) begin
          nstat = UU;
        end else if (inp1 == INP_Y) begin
          nstat = VV;
        end
      end

      VV: begin
        nstat = VV;
        if (inp2 == INP_X && !maxedout ) begin
          nstat = VV;
        end else if (inp2 == INP_X && maxedout) begin
          nstat = UU;
        end else if (inp2 == INP_Y && !maxedout) begin
          nstat = WW;
        end else if (inp2 == INP_Y && maxedout) begin
          nstat = WW;
        end
      end

      WW: begin
        nstat = WW;
        if (inp2 == INP_X) begin
          nstat = WW;
        end else if (inp2 == INP_Y) begin
          nstat = XX;
        end
      end

      XX: begin
        nstat = XX;
        if (inp1 == INP_X && maxedout == 1'b0 ) begin
          nstat = XX;
        end else if (inp1 == INP_X && maxedout == 1'b1) begin
          nstat = WW;
        end else if (inp1 == INP_Y && maxedout == 1'b0) begin
          nstat = UU;
        end else if (inp1 == INP_Y && maxedout == 1'b1) begin
          nstat = UU;
        end
      end

      default: nstat = UU;
    endcase
  end

  always @ ( * ) begin
    case (cstat)
      UU, VV:   oup1 = OUP_X;
      WW, XX:   oup1 = OUP_Y;
      default:  oup1 = OUP_X;
    endcase
  end
endmodule

Testbench

`timescale 1ms / 1us

module moore_fsm_tb;

  reg clk;
  reg rst;
  reg inp1;
  reg inp2;

  wire oup1;
  wire [1:0] cstat;
  wire [1:0] nstat;

  localparam  TIME_PERIOD = 1;

  localparam  INP_X = 1'b0;
  localparam  INP_Y = 1'b1;
  localparam  OUP_X = 1'b0;
  localparam  OUP_Y = 1'b1;

  localparam  UU = 2'b00;
  localparam  VV = 2'b01;
  localparam  WW = 2'b10;
  localparam  XX = 2'b11;

  moore_fsm_top dut(.clk(clk),
                     .rst(rst),
                     .inp1(inp1),
                     .inp2(inp2),
                     .oup1(oup1),
                     .cstat(cstat),
                     .nstat(nstat));


  initial begin
    clk = 1'b0;
    forever #(TIME_PERIOD/2) clk = ~clk;
  end

  initial begin
    rst = 1'b1;
    @(negedge clk);
    @(negedge clk);
    rst = 1'b0;
  end

  initial begin
    inp1 = INP_X;
    inp2 = INP_X;

    @(negedge rst);

    checkifgood(UU, UU, OUP_X);

    $display("PASS");
    $finish;
  end

  task checkifgood;
    input [1:0] exp_cstat;
    input [1:0] exp_nstat;
    input exp_oup1;

    if (oup1 !== exp_oup1 || cstat !== exp_cstat || nstat !== exp_nstat) begin
      $display("FAILED");
      $display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
               $time, rst, inp1, inp2, cstat, nstat, oup1 );
      $display("Expected current state = %b, next state = %b, oup1 = %d",
                exp_cstat, exp_nstat, exp_oup1 );
      $finish;
    end else begin
    $display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
             $time, rst, inp1, inp2, cstat, nstat, oup1 );
    end
  endtask

endmodule

I read Verilog gotcha that for asynchronous resets, if clocking and reset are in different initial blocks, than I should initialize clock and reset with non-blocking statement. If I make this change in above testbench, I get output from simulator saying:

Execution interrupted or reached maximum runtime.

What is going wrong here ?

\$\endgroup\$
6
  • \$\begingroup\$ @ElliotAlderson Yes. But UU = 2'b00 and it shows cstat instead as xx. reset is asynchronous active high. Its held high for 2 negedges of clk and goes to 0 after that. by that time cstat should be 0. but it isn't \$\endgroup\$
    – nurabha
    Mar 9 '20 at 19:59
  • \$\begingroup\$ @BrianDrummond Oops, I didn't see that. I will delete my comment. Thanks for pointing out my mistake. \$\endgroup\$ Mar 9 '20 at 20:02
  • \$\begingroup\$ "I read Verilog gotcha..." That is nonsense. I always use reset_n= 1'b0; #(TIME_PERIOD*10); reset_n= 1'b1; I also prefer my TIME_PERIOD to be a nice big number 50 or 100 , not 1! OH! Just quickly scanning your code this is wrong: ncnt = ncnt+1; That does not work in a combinatorial section. \$\endgroup\$
    – Oldfart
    Mar 9 '20 at 21:16
  • \$\begingroup\$ Found more: you are changing ncnt in different sections. You can't do that . 1/ It gives race conditions 2/ You can not synthesize that. \$\endgroup\$
    – Oldfart
    Mar 9 '20 at 21:23
  • \$\begingroup\$ @Oldfart thanks for pointing those out. Those were unintentionally done when I was obfuscating the code. I fixed them. But sill getting xx in current state and output indicating design is not getting reset: FAILED Time=0, rst=0, inp1=0, inp2=0, current state = xx, next state = 00, oup1 = x Expected current state = 00, next state = 00, oup1 = 0 \$\endgroup\$
    – nurabha
    Mar 12 '20 at 3:12
1
\$\begingroup\$

I have modified your Test Bench and Design code, now u wont encounter the crash issue but i definitely think there is an issue in your stimulus in Test Bench.

`timescale 1ns / 1ns

module moore_fsm_tb;

  reg clk;
  reg rst;
  reg inp1;
  reg inp2;

  wire oup1;
  wire [1:0] cstat;
  wire [1:0] nstat;

  localparam  TIME_PERIOD = 2;

  localparam  INP_X = 1'b0;
  localparam  INP_Y = 1'b1;
  localparam  OUP_X = 1'b0;
  localparam  OUP_Y = 1'b1;

  localparam  UU = 2'b00;
  localparam  VV = 2'b01;
  localparam  WW = 2'b10;
  localparam  XX = 2'b11;

  moore_fsm_top dut(.clk(clk),
                     .rst(rst),
                     .inp1(inp1),
                     .inp2(inp2),
                     .oup1(oup1),
                     .cstat(cstat),
                     .nstat(nstat));


  initial 
    clk = 1'b0;
     always #(TIME_PERIOD/2) clk = ~clk;


  initial begin
    rst = 1'b0;
    @(negedge clk);
    @(negedge clk);
    rst = 1'b1;

    @(negedge clk);
    @(negedge clk);
    rst = 1'b0;
  end

  initial begin
    inp1 = INP_X;
    inp2 = INP_X;

    @(negedge rst);

    checkifgood(UU, UU, OUP_X);

    $display("PASS");
    $finish;
  end

  task checkifgood;
    input [1:0] exp_cstat;
    input [1:0] exp_nstat;
    input exp_oup1;

    if (oup1 !== exp_oup1 || cstat !== exp_cstat || nstat !== exp_nstat) begin
      $display("FAILED");
      $display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
               $time, rst, inp1, inp2, cstat, nstat, oup1 );
      $display("Expected current state = %b, next state = %b, oup1 = %d",
                exp_cstat, exp_nstat, exp_oup1 );
      $finish;
    end else begin
    $display("Time=%0d, rst=%0b, inp1=%d, inp2=%d, current state = %b, next state = %b, oup1 = %d",
             $time, rst, inp1, inp2, cstat, nstat, oup1 );
    end
  endtask

endmodule

design code also modified ,but i am not sure u are trying to implement a priority encoders using the nested if-else-if structure in your design , but with initial glance i think u are not intended to do it.

module moore_fsm_top (
   input wire       clk,rst,inp1,inp2
  ,output reg       oup1
  ,output reg [1:0] cstat,nstat
 );

  localparam  MAX = 4000;
  reg [11:0] ccnt;
  reg [11:0] ncnt;
  wire maxedout;

  localparam  INP_X = 1'b0;
  localparam  INP_Y = 1'b1;
  localparam  OUP_X = 1'b0;
  localparam  OUP_Y = 1'b1;

  localparam  UU = 2'b00;
  localparam  VV = 2'b01;
  localparam  WW = 2'b10;
  localparam  XX = 2'b11;

 always @ ( posedge clk, posedge rst )
    if ( rst ) begin
      cstat <= #1 UU;
      ccnt  <= #1 12'b0;
    end else begin
      cstat <= #1 nstat;
      ccnt  <= #1 ncnt;
    end

  always @*
      case (cstat)
        UU, WW:                      ncnt = 12'b0;
        VV, XX: if (ccnt == (MAX-1)) ncnt = 12'b0;
                else                 ncnt = ccnt+1;
    endcase

  assign maxedout = (ccnt == (MAX-1)) ? 1'b1 : 1'b0;

   always@* begin
                                                 nstat = cstat;
    case (cstat)
      UU:        if (inp1 == INP_Y)              nstat = VV;

      VV:        if (inp2 == INP_X &&  maxedout) nstat = UU;
            else if (inp2 == INP_Y )             nstat = WW;

      WW:        if (inp2 == INP_Y)              nstat = XX;

      XX:        if (inp1 == INP_X &&  maxedout) nstat = WW;
            else if (inp1 == INP_Y )             nstat = UU;
    endcase
  end

  always @*
    case (cstat)
      WW, XX:   oup1 = OUP_Y;
      default:  oup1 = OUP_X;
    endcase

endmodule 
\$\endgroup\$
2
  • \$\begingroup\$ dear rama. I already found the problem and fixed it with help of @oldfart. The problem in design was not deliberate. I was obfuscating the code before I posted it here and it introduced the problem. The problem was there in Test-bench. It was basically that time period of 1 was not letting simulator proceed. Dividing time period of 1 (1 ms) by 2 in clock generation was perhaps causing it. Not sure why that is so because it should still work as time precision or step size is 1 us and so simulator should be able to generate 500 us clock edges \$\endgroup\$
    – nurabha
    Mar 15 '20 at 1:54
  • \$\begingroup\$ I think you have used localparam in the test bench by default localparam is an integer so if you divide 1 by 2 it might have rounded it to 0 so your test bench is not moving ahead and it is using up the memory, and regarding the current state is xxx, this is because in the initial block u are asserting the reset from timestamp 0 so design won't see as posedge in reset and your design won't get reset asynchronously.. So I modified the localparam,reset assertion and time precision in the Test Bench. \$\endgroup\$ Mar 15 '20 at 3:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.