membersound
membersound

Reputation: 86865

How does a simple state machine look in Verilog?

I'm trying to convert a flow chart simple state machine into Verilog code. But I'm somehow stuck with the following, and as I have hardly any knowledge in Verilog I'm probably missing something.

The statemachine detects for an input stream of 0 and 1, if the count of 1s can be divided by 3 (or simply: if there have been 3 times number 1).

enter image description here

module example (
  input clk,
  input rst,
  input input1,
  output output
);

reg state;
reg nextstate;

localparam state2 = 3'd0;
localparam state1 = 3'd1;
localparam state0 = 3'd2;

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

always @* begin
  case(state)
    state0: begin
      if(input1)
        nextstate = state1;
      end
    state2: begin
      if(input1)
        nextstate = state0;
      end
    state1: begin
      if(input1)
        nextstate = state2;
      end
    default: nextstate = state0;
  endcase
end

always @* begin
  output1 = state0 & input1;
end

endmodule

I'm not sure:

Upvotes: 5

Views: 13806

Answers (3)

JYasir
JYasir

Reputation: 43

Although its too late but i got on the band wagon of learning Verilog and decided to take a shot at your inquiry. I wrote the design module and also created a test bench for it. This works according to your expectation.

`timescale 1ns/1ns
`define WIDTH 4
module FSM_Detect_Stream_Top();

    reg in_clk;
    reg in_rst_n;
    reg [`WIDTH-1:0] in_input;

    wire out_ouput;

    FSM Test (.i_clk(in_clk), .i_rst_n(in_rst_n), .i_input(in_input), .o_output(out_output));

    initial
        begin
            in_clk = 1'b0; // clk at t=0
            #1 in_rst_n = 1'b1;
            #2 in_rst_n = 1'b0;
            #5 in_rst_n = 1'b1;
            @ (negedge in_clk)
                in_input = 2'b01;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_input = 2'b01;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_input = 2'b01;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_input = 2'b01;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_input = 2'b01;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_input = 2'b00;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_rst_n = 1'b0;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            @ (negedge in_clk)
                in_input = 2'b00; in_rst_n = 1'b1;
            @ (posedge in_clk)  
                $display("output:%b ", out_output);
            $finish;
        end


    // Generating a 20ns width clock pulse with 50% duty cycle
    always
        #10 in_clk = ~in_clk;

endmodule // FSM_Detect_Stream_Top

//*********************************************************************************************
module FSM(input i_clk, input i_rst_n, input [`WIDTH-1:0] i_input, output reg o_output);
//*********************************************************************************************

    parameter S0 = 2'b00;   //FIRST STATE or DEFAULT
    parameter S1 = 2'b01;   //SECOND STATE
    parameter S2 = 2'b10;   //THIRD STATE
    parameter S3 = 2'b11;   //FOURTH STATE

    reg [`WIDTH-3:0] curr_state;
    reg [`WIDTH-3:0] next_state;

    //Sequential Logic for Storing Current State
    always @ (posedge i_clk or negedge i_rst_n) begin
        if(~i_rst_n)
            curr_state <= S0;
        else
            curr_state <= next_state;
        end

    //Combinational Logic for Next State
    always @ (curr_state or i_input)    begin
        case(curr_state)
            S0: begin
                if (i_input == 2'b01)
                    next_state <= S1;
                else
                    next_state <= S0;
            end
            S1: begin
                if (i_input == 2'b01)
                    next_state <= S2;
                else
                    next_state <= S1;
            end
            S2: begin
                if (i_input == 2'b01)
                    next_state <= S3;
                else
                    next_state <= S2;
            end
            S3: begin
                if (i_input == 2'b01)
                    next_state <= S0;
                else
                    next_state <= S3;
            end 
            default: next_state <= S0;
        endcase // curr_state
    end

    // Output Logic
    always @(posedge i_clk) begin
        if (~i_rst_n)
            o_output <= 1'b0;
        else begin
            case(curr_state)    
                S0: begin
                    if (i_input == 2'b01)
                        o_output <= 1'b1;
                    else
                        o_output <= 1'b1;
                    end
                S1: begin
                    if (i_input == 2'b01)
                        o_output <= 1'b1;
                    else
                        o_output <= 1'b0;
                    end
                S2: begin
                    if (i_input == 2'b01)
                        o_output <= 1'b1;
                    else 
                        o_output <= 1'b0;
                    end
                S3: begin
                    if (i_input == 2'b01)
                        o_output <= 1'b1;
                    else 
                        o_output <= 1'b0;
                    end
                default: o_output <= 1'b0;
            endcase
        end
    end 

endmodule

Upvotes: 2

chitranna
chitranna

Reputation: 1639

always @* begin
  case(state)
    state0: begin
      if(input1)begin
        nextstate = state1;
         output1 = 0;
      end end
       else begin
        nextstate = state0;
         output1 = 1;
      end
    state2: begin
      if(input1)begin
        nextstate = state0;
        output1   = 1 ;
      end end
      begin
        nextstate = state2;
         output1 = 0;
      end
    state1: begin
      if(input1)begin
        nextstate = state2;
        output1   = 0;
      end end
     else begin
        nextstate = state1;
         output1 = 0;
      end
    default: nextstate = state0;
  endcase
end

Upvotes: 2

Tim
Tim

Reputation: 35943

do I have to define the inputs + outputs as reg or wire? Or is input and output! sufficient?

Inputs are always wires, though it doesn't really matter as you don't assign to them. Outputs are wires by default, though you can also declare output reg if you want a register instead.

must I provide a vector dimension for the reg state, nextstate? If yes, how to I know which dimension to pick?

Yes you must declare a dimension, or else your design will catastrophically fail when verilog silently truncates all your states to 0 or 1. The width of the states should be the same width of the localparams that you use to define the state names, or more generically the width should be log2(number of input states).

can I write these kind of assertions at the end like state0 & input1?

I don't think this is what you want. State0 is just a constant number. If you want to know if the state machine is in state0, then you need to compare the current state with the constant state0. Also you likely don't want a bitwise AND here, so use the regular and &&. Should be:

output = (state == state0) && input1;

Upvotes: 2

Related Questions