I'm designing a finite state machine (FSM) to detect the sequence "10001" in Verilog.
I'm having a similar problem to that described in this question in that my FSM does not tick when the sequence is seen but the solution to that problem does not apply in my case.
This is my FSM design: enter image description here
Here is my verilog code for the FSM.
module fsm_detector(
input wire clk, reset,
input wire sequence,
output reg tick
);
// FSM state declarations
parameter A = 3'b000;
parameter B = 3'b001;
parameter C = 3'b010;
parameter D = 3'b011;
parameter E = 3'b100;
//signal declaration
reg [2:0] state_reg;
reg [2:0] state_next;
// state register logic
// asynchrous reset
always @(posedge clk, posedge reset)
if(reset)
state_reg <= A;
else
state_reg <= state_next;
//next-state logic and output logic
always @ *
begin
state_next = state_reg; // default state: the same
tick = 1'b0; // default tick = 0
case(state_reg)
A: if(sequence) // sequence = 1
state_next = B;
// else stay in A
B: if (~sequence)
state_next = C;
// else stay in B
C:
if (~sequence)
state_next = D;
else
state_next = B;
D:
if(~sequence)
state_next = E;
else
state_next = B;
E: if(sequence)
begin
tick = 1'b1;
state_next = B;
end
else
state_next = A;
default:
state_next = A;
endcase
end
endmodule
And testbench:
`timescale 1ns / 1ns
module fsm_detector_tb();
//declerations
parameter T = 20; //clock period in nanoseconds
reg clk, reset;
reg test_input;
wire test_tick;
fsm_detector uut(
.clk(clk),
.reset(reset),
.sequence(test_input),
.tick(test_tick)
);
// clock
// 20 ns clock running forever
always
begin
clk = 1'b1; //high
#(T/2); // delay half a period
clk = 1'b0; //low
#(T/2); // delay half a period
end
initial
begin
reset = 1'b1;
test_input = 1'b0;
#(2*T); // delay two clock cycle
reset = 1'b0;
test_input = 1'b0;
#(T); // delay one clock cycle
test_input = 1'b0;
#(T); // delay one clock cycle
test_input = 1'b1;
#(T); // delay one clock cycle
test_input = 1'b0;
#(T); // delay one clock cycle
test_input = 1'b0;
#(T); // delay one clock cycle
test_input = 1'b0;
#(T); // delay one clock cycle
test_input = 1'b1;
#(T); // delay one clock cycle
test_input = 1'b1;
#(T); // delay one clock cycle
test_input = 1'b0;
#(T); // delay one clock cycle
$finish;
end
endmodule
The FSM should tick high at the point marked below:
Any suggestions?
Simulation output showing state transitions: enter image description here
-
\$\begingroup\$ Look at the internal signals to see if the state is changing at all. \$\endgroup\$Matt– Matt2019年04月10日 22:27:57 +00:00Commented Apr 10, 2019 at 22:27
-
\$\begingroup\$ @Matt The internal 'state_reg' signal changes as follows: state_reg = X 0 0 1 1 2 3 4 4 1 . sequence = 0 0 1 1 0 0 0 0 1 1 \$\endgroup\$Ciarán– Ciarán2019年04月10日 22:33:17 +00:00Commented Apr 10, 2019 at 22:33
-
\$\begingroup\$ So you did go from E back to B (4 to 1) which should trigger your output. I don't know. Did you confirm that tick didn't assert inside the dut (just to make sure your connections are sound)? \$\endgroup\$Matt– Matt2019年04月10日 22:43:17 +00:00Commented Apr 10, 2019 at 22:43
-
1\$\begingroup\$ Wait you stayed in E for 2 consecutive cycles. That's impossible according to your verilog. Are you sure you're looking at the latest waves? \$\endgroup\$Matt– Matt2019年04月10日 22:45:02 +00:00Commented Apr 10, 2019 at 22:45
-
\$\begingroup\$ In the tb you use blocking assignments for both clk and signal. I don't remember offhand but I think I use nonblocking for signals and blocking for clk. You might have a classic verilog race condition. \$\endgroup\$Matt– Matt2019年04月10日 22:47:18 +00:00Commented Apr 10, 2019 at 22:47
2 Answers 2
Signal (non clock) assignments in a testbench should generally be non blocking (<= operator). Clock assignments should be blocking (= operator). Otherwise there's a race condition.
There are probably exceptions to this rule, but it works for me. Beyond that you need a good understanding of the verilog simulation phases. This rule of thumb will work for you 95% of the time.
This is due to the race condition in your code at state assignment , usually people will use #TCQ in NBA assignment and to look similar to hardware transiton.
module fsm_detector(
input wire clk, reset,
input wire sequence,
output reg tick
);
// FSM state declarations
parameter A = 3'b000;
parameter B = 3'b001;
parameter C = 3'b010;
parameter D = 3'b011;
parameter E = 3'b100;
//signal declaration
reg [2:0] state;
reg [2:0] next;
// state register logic
// asynchrous reset
always @(posedge clk, posedge reset)
if(reset) state <= #10 A;
else state <= #10 next;
//next-state logic and output logic
always @ * begin
next = state; // default state: the same
tick = 1'b0; // default tick = 0
case(state)
A: if ( sequence) next = B;
B: if (~sequence) next = C;
C: if (~sequence) next = D;
else next = B;
D: if (~sequence) next = E;
else next = B;
E: if ( sequence) begin
tick = 1'b1;
next = B;
end else next = A;
default: next = A;
endcase
end
endmodule
Simulation output with modified code and adding #TCQ to NBA(Non-Blocking Assignments) assignments enter image description here
Explore related questions
See similar questions with these tags.