Search code examples
verilogsystem-verilogfsm

FSM stuck at one state


I am developing an FSM to latch on to incoming data and compute its average in Verilog, but my FSM seems to be just stuck at one state.

Although the simulation shows it shifted perfectly in previous states, but it is stuck at the filter_data_64 state.

    `timescale 1ps/1ps

module amf_ctrl #(
parameter data_bits    = 64,
parameter average_cont = 16
)
(
    input            clk,
    input            rst,
    input            vld,
    input           last,
    output           rdy,
    input [7:0] data_flit,
    input [5:0] valid_bytes,
    output [7:0] filter_data_o,
    output           done
    );
        
    reg [7:0] data_buff [data_bits-1:0]; 
    reg [data_bits-1:0] byte_cont;
    reg [7:0] avg_cont, byte_cont_64, filter_data; 
    reg [3:0] state;
    reg [3:0] nextstate;
    reg [7:0] r0, r1, r2, r3, sum_reg;
    reg [5:0] valid_no;
    reg done_sig, rdy_sig, vld_dly, vld_pe, byte_64_en;
    assign done = done_sig; 
    assign filter_data_o = filter_data;
    assign rdy = rdy_sig;
    ////////////////////////////////////////
    parameter idle = 4'b0000, buffer_data = 4'b0001, buffer_data_1 = 4'b0010, filter_data_state = 4'b0011;
    parameter Avg_cal = 4'b0100, Sum_data = 4'b0101, Shift_data = 4'b0110, Result_data = 4'b0111;
    parameter filter_data_64 = 4'b1000, Sum_data_64 = 4'b1001, Shift_data_64 = 4'b1010, Result_data_64 = 4'b1011;
    ////////////////////////////
    always @ (posedge clk) begin
        vld_dly <= vld;
    end
    ////////////////////////////
    // Detect no of valid Bytes //
    always @ (posedge clk or negedge rst) begin
         if (~rst) begin
             valid_no <= 5'b00000;
             byte_64_en <= 1'b0;end
             
        else if (last) begin 
                 valid_no <= valid_bytes;
             
          if(valid_bytes == 0)
             byte_64_en <= 1'b1;end
             
         
         else begin     
            byte_64_en <= 1'b0;
         end            
    end
    ////////////////////////////
    always @(posedge clk or negedge rst) 
    
      if ((~rst)||(byte_cont==data_bits-1)) 
          byte_cont <= 0;
     else     
        if (!vld & vld_dly) begin
            byte_cont <= byte_cont + 1;
            data_buff[byte_cont] <= data_flit;
      end   
   ////////////////////////////////////
   always @(posedge clk) begin
       if (~rst) begin
           done_sig  <= 1'b0;
           rdy_sig   <= 1'b0 ;
           sum_reg   <= 8'h00;
           filter_data <= 8'h00;
           avg_cont    <= 8'h00;
           state <= idle;
         end  
        else begin     
              case(state)
                    idle:begin    
                        if(vld)begin
                           rdy_sig <= 1'b1;
                           nextstate <= buffer_data;
                        end 
                        else if (last)begin
                            rdy_sig  <= 1'b0;
                            nextstate <= filter_data_state;end 
          
                        else begin   
                          rdy_sig <= 1'b0;
                          nextstate <= idle;end
                        end 
                    ////////////////////////////////////     
                    buffer_data:begin
                               rdy_sig <= 1'b0;
                               nextstate <= idle; 
                     end        
                    //////////////////////////////////
                    filter_data_state:begin
                      //if(byte_64_en)begin 
                         //rdy_sig <= 1'b0;
                         //avg_cont     <= average_cont;
                         //byte_cont_64 <= data_bits - 1;
                         //nextstate <= filter_data_64;end
                         
                         
                      //else if (byte_64_en)begin
                      //else begin
                         //rdy_sig <= 1'b0;
                         nextstate <= Avg_cal;//end
                         
                      end                     
                      //////////////////////////////////
                      Avg_cal:begin
                      if(valid_no == 0)begin
                         done_sig <= 1'b0;                    
                         nextstate = idle;
                        end 
                      else begin
                         done_sig <= 1'b0;
                         r0 <= data_buff[valid_no];
                         r1 <= data_buff[valid_no - 1]; 
                         r2 <= data_buff[valid_no - 2];
                         r3 <= data_buff[valid_no - 3]; 
                         valid_no <= valid_no - 4;
                         nextstate = Sum_data;end
                      end    
                      /////////////////////////////////
                      Sum_data: begin
                            sum_reg <= r0 + r1 + r2 +r3;
                            nextstate <= Shift_data;
                            end
                     /////////////////////////////////
                     Shift_data: begin
                            sum_reg <= sum_reg >> 2; 
                            nextstate <= Result_data;
                            end
                     /////////////////////////////////      
                     Result_data: begin
                            filter_data <= sum_reg;
                            done_sig <= 1'b1;                           
                            nextstate <= Avg_cal;
                            end                         
                     ////////////////////////////// 
                     filter_data_64:begin
                          if(avg_cont == 0)begin 
                             done_sig <= 1'b0;                    
                             nextstate <= idle;
                            end 
                          else begin
                             done_sig <= 1'b0;
                             r0 <= data_buff[byte_cont_64];
                             r1 <= data_buff[byte_cont_64 - 1]; 
                             r2 <= data_buff[byte_cont_64 - 2];
                             r3 <= data_buff[byte_cont_64 - 3];
                             byte_cont_64 <= byte_cont_64 - 4;                           
                             avg_cont <= avg_cont - 1;
                             nextstate <= Sum_data_64;end
                      end        
                     ////////////////////////////////////
                     Sum_data_64: begin
                                      sum_reg <= r0 + r1 + r2 +r3;
                                      nextstate <= Shift_data_64;
                                   end
                     ///////////////////////////////////
                     Shift_data_64: begin
                                        sum_reg <= sum_reg >> 2; 
                                        nextstate <= Result_data_64;
                                    end
                     /////////////////////////////////      
                     Result_data_64: begin
                            filter_data <= sum_reg;
                            done_sig <= 1'b1;                           
                            nextstate <= filter_data_64;    
                            end                             
                                 
                     
                     
  endcase
 end 
end 
endmodule
////////////////////

/* Verilog test bench : it simulates AXI slave as per document "AMBA® 4 AXI4-Stream Protocol Version: 1.0 Specification" */

// Testbench //
`timescale 1ps/1ps
module tb_amf_ctrl();

reg     tb_clk;             // To drive input "d" of the DUT
reg     tb_rst;         // To drive input "en" of the DUT
reg     tb_vld;         // To drive input "rstn" of the DUT
reg     tb_last;    // To ensure q has not changed when en=0
wire    tb_rdy;             // To tap output "q" from DUT
wire    tb_done; 
reg     [7:0] tb_data_flit;
reg     [5:0] tb_vld_bytes;
wire    [7:0] tb_filter_data_o;

amf_ctrl DUT (
                      .clk(tb_clk),
                      .rst(tb_rst),
                      .vld(tb_vld),
                      .last(tb_last),
                      .rdy(tb_rdy),
                      .data_flit(tb_data_flit),
                      .valid_bytes(tb_vld_bytes),
                      .filter_data_o(tb_filter_data_o),
                      .done(tb_done)
                      );
// Clock //
initial tb_clk = 0;                   
  always #5 tb_clk = ~tb_clk;           
/////////////////////////
//////////      
initial begin
    tb_rst  <= 1'b0;
    tb_vld  <= 1'b0;
    tb_last <= 1'b0;
    tb_data_flit <= 8'h00;
    tb_vld_bytes <= 6'b000000;
    #30;
    tb_rst <= 1'b1;
    #10;
    //1st byte
    tb_vld  <= 1'b1;
    tb_data_flit <= 8'h11;
    #20;
    tb_vld  <= 1'b0;
    #20;
    //2nd byte
    tb_vld  <= 1'b1;
    tb_data_flit <= 8'h02;
    #20;
    tb_vld  <= 1'b0;
    #20;
    //3rd byte
    tb_vld  <= 1'b1;
    tb_data_flit <= 8'h03;
    #20;
    tb_vld  <= 1'b0;
    #20;
    //4th byte
    tb_vld  <= 1'b1;
    tb_data_flit <= 8'h04;
    #20;
    tb_vld  <= 1'b0;
    #20;
    //// Last ////
    #10;
    tb_last <= 1'b1;
    tb_vld_bytes <= 6'b000100;
    //tb_vld_bytes <= 6'b000000;
    #50;
    $finish(2);
end         

endmodule
//////////////////////////////////////

Modelsim simulation :

waves


Solution

  • The problem with your code is that you only make one assignment to the state signal during reset:

           state <= idle;
    

    state is always idle. You didn't show state in your waveform image, but you should be able to see that it is always idle.

    This following line:

    case(state)
    

    means that you only execute the following case item:

    idle:begin
    

    You never execute any other item in the case statement. Although nextstate is assigned to filter_data_state, state is not. You need to fix the FSM.

    Typically, when you code an FSM in Verilog using both (current) state and nextstate signals, you would use 2 separate always blocks:

    • one for sequential logic where you assign to state
    • the other for combinational logic where you assign to nextstate

    It is possible to code an FSM with a single always block, but then you would typically just have a state signal, without a next-state signal. In other words, your FSM does not adhere to common practices.

    For example, refer to this FSM code to see the style.

    See also: FSM Conditional counter