Intel® FPGA University Program
University Program Material, Education Boards, and Laboratory Exercises
1235 Discussions

Verilog FSM stuck on one State forever

Fpga_Egr_2025
Beginner
1,310 Views

I am developing a 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 did shifted perfectly in previous states, but it is stuck at "filter_data_64" state . See complete code below :

 

`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" */
//////////////////////////////////////////////////////////////////////////////
`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

 

Labels (3)
0 Kudos
1 Solution
RichardTanSY_Altera
1,251 Views

You have nextstate in your case statement, but state never updates to nextstate.

Fix it by adding a sequential block to update state at every clock edge.

 

always @(posedge clk) begin
  if (~rst)
    state <= idle;
  else
    state <= nextstate;
end

 

I would recommend to checkout 'Two Always Block FSM coding style' from the article below.

It uses two separate always blocks:

  1. State Register Block: A sequential (always_ff ) block that updates the current state (state_reg) on the clock edge.
  2. Next State & Output Logic Block: A combinational (always_comb) block that determines the next state and the outputs based on the current state and inputs.

http://www.sunburst-design.com/papers/CummingsSNUG2019SV_FSM1.pdf

 

Regards,

Richard Tan

 

View solution in original post

0 Kudos
5 Replies
Fpga_Egr_2025
Beginner
1,296 Views

Here is the simulation results

 

sim_results.JPG

0 Kudos
RichardTanSY_Altera
1,252 Views

You have nextstate in your case statement, but state never updates to nextstate.

Fix it by adding a sequential block to update state at every clock edge.

 

always @(posedge clk) begin
  if (~rst)
    state <= idle;
  else
    state <= nextstate;
end

 

I would recommend to checkout 'Two Always Block FSM coding style' from the article below.

It uses two separate always blocks:

  1. State Register Block: A sequential (always_ff ) block that updates the current state (state_reg) on the clock edge.
  2. Next State & Output Logic Block: A combinational (always_comb) block that determines the next state and the outputs based on the current state and inputs.

http://www.sunburst-design.com/papers/CummingsSNUG2019SV_FSM1.pdf

 

Regards,

Richard Tan

 

0 Kudos
Fpga_Egr_2025
Beginner
1,190 Views

HI Richard,

 

Yes changed the fsm to have two separate always block :

 

////////////////////////////////////
   always @ (posedge clk) begin
    if (~rst) begin
        state <= idle;end
else begin
        state <= nextstate;end
   end
   ////////////////////////////////////
   always @(*) begin
   
         nextstate <= idle;
 
     case(state)
 
idle:begin  
                         
    if(vld)begin
   rdy_sig <= 1'b1;
                           nextstate <= buffer_data;
end 
else if (last)begin
    rdy_sig      <= 1'b0;
valid_no_reg <= valid_no;
nextstate    <= filter_data_state;end 
0 Kudos
RichardTanSY_Altera
1,201 Views

Dropping a note to ask if my last reply was helpful to you.

Do you able to resolve the issue? 


Regards,

Richard Tan


0 Kudos
RichardTanSY_Altera
1,181 Views

Thank you for acknowledging the solution provided. I'm pleased to know that your question has been addressed. 


Now, I will transitioning this thread to community support. If you have any further questions or concerns, please don't hesitate to reach out. Please login to https://supporttickets.intel.com/s/?language=en_US , view details of the desire request, and post a feed/response within the next 15 days to allow me to continue to support you. After 15 days, this thread will be transitioned to community support.

The community users will be able to help you on your follow-up questions.


Thank you and have a great day!


Best Regards,

Richard Tan


0 Kudos
Reply