2
\$\begingroup\$

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:

Simulation output

Any suggestions?

Simulation output showing state transitions: enter image description here

\$\endgroup\$
  • \$\begingroup\$ Look at the internal signals to see if the state is changing at all. \$\endgroup\$ – Matt Apr 10 '19 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 Apr 10 '19 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 Apr 10 '19 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 Apr 10 '19 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 Apr 10 '19 at 22:47
2
\$\begingroup\$

Signal assignments should be non blocking. Otherwise there's a race condition.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

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

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.