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 :
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:
state
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