Search code examples
verilogstate-machine

Modelling of a FSM using Verilog shows X


Given the following FSM:

enter image description here

I am trying to model it using Verilog, and here is my trial:

module fsm (u,d,clr,clk,inc,dec,c);
  
input  u,d, clr,clk;
output reg inc,dec,c ;
// the state variables
reg y,Y; // y is the present state and Y is the next state
reg S0,S1;  

  // next state and output specifications 
 
  always @ (y,u,d) begin 
    
    case (y)
      S0 : if (u==1) begin
        Y= S1;
        inc=1;
        dec=0;
        c=1;
      end
      else if (u==0) begin
        c=0;
      end
      S1 :  if (d==1) begin
         Y= S0;
         inc=0;
         dec=1;
         c=0;
      end
      else if (d==0) begin
            c=1;
      end
   endcase 
  end 
  // state update
    always @(posedge clk,clr) begin
      if (clr) 
        y=S0;
      else 
        y=Y;
    end
    endmodule

Please let me know if my code correctly describes this FSM, and if there is any enhancement in the code please let me know it.

Here is an initial test bench code:

module tb();
 reg u,d, clr,clk;
reg inc,dec,c,y ;
  
  fsm ttb (.u(u),.d(d),.clk(clk),.clr(clr),.inc(inc),.dec(dec),.c(c));
  
     initial begin 
    $dumpfile("dump.vcd");
    $dumpvars;
  end 
  
  initial begin //{
   clk=0 ; clr=0; #10
    clk=1; u=0 ; clr=0 ; d=0; #10
    clk = 0;#10
    u=1; clk=1; #10
   
    
    
    
    
    $finish;
    
    
    
    
  end //}
  
endmodule

The testbench code shows that there is something wrong. The present state variable y shows an undefined value 'X'. I don't know why. The same for the output variables inc and dec.

enter image description here


Solution

  • There are several causes for the X's.

    In the design, you declared S0 and S1 as reg, but then you never assigned values to them. A Verilog reg is initialized to X. An FSM is conventionally coded using constant parameter values. For example, change:

    reg S0,S1;  
    

    to:

    parameter S0=0, S1=1;  
    

    Your next state logic needs to assign values to Y in all cases (refer to <---):

      always @ (y,u,d) begin 
        case (y)
          S0 : if (u==1) begin
            Y= S1;
            inc=1;
            dec=0;
            c=1;
          end
          else if (u==0) begin
            c=0;
            Y= S0; // <-----
          end
          S1 :  if (d==1) begin
             Y= S0;
             inc=0;
             dec=1;
             c=0;
          end
          else if (d==0) begin
                c=1;
                Y= S1; // <-----
          end
       endcase 
      end 
    

    In your testbench, you need to assert the reset (clr=1):

      initial begin
        u=0; d=0;
        clk=0 ; clr=1; #10
        clk=1; u=0 ; d=0; #10
        clk = 0;#10
        u=1; clk=1; clr=0; #10
        $finish; 
      end
    

    Addressing the comments on your Question regarding the asynchronous clear, you should change:

    always @(posedge clk,clr) begin
    

    to:

    always @(posedge clk, posegde clr) begin