# Verilog State Machine?

in Verilog

What is the best way to implement a state machine in Verilog?

by (300 points)

Basically, a FSM consists fo three parts: Combinational logic, Sequential logic (flip-flops), Output logic. Purposes of these three parts are:

Combinational logic - to decide the next state of a FSM
Sequential logic - to store the state of a FSM
Output logic - to specify data processing based on the cuurent state of FSM and in the implementation sense is a mix of the combinational and the sequential logic.

The best way is to separate these parts from each other. But if a FSM is simple, it is possible to combine either the Combinational and the Sequential parts or even all three parts in a single always-block.

Example 1:

``  reg [1:0] state, state_next;  localparam StIdle  = 2'b00;  localparam StWait  = 2'b01;  localparam StShift = 2'b10;  localparam lpBufferWidth = 1 + pDataWidth + pParity;  reg [lpBufferWidth-1:0] buffer;  localparam lpPacketWidth = lpBufferWidth + pStopBits;  reg [\$clog2(lpPacketWidth)-1:0] BitCnt;  reg [15:0] BitCellCnt;  reg done = 0;  assign oDone = done & ~en;  // Combinational logic  always @(*) begin    state_next = state;    if (rst) begin      state_next = StIdle;    end    case(state)        StIdle:begin              if (en) state_next = StWait;          end        StWait:begin              if (BitCellCnt == lpBitCellWidth)                state_next = StShift;          end         StShift:begin              if (BitCnt == lpPacketWidth-1)                state_next = StIdle;              else                state_next = StWait;          end        default: begin              state_next = StIdle;          end    endcase  end  // Sequential logic  always @(posedge clk) state <= state_next;  // Output logic  always @(posedge rst, posedge clk)    if (rst) begin        BitCnt <= 0;        BitCellCnt <= 0;        buffer <= {lpBufferWidth{1'b1}};        done <= 1;      end    else begin      case(state)          default: begin                state <= StIdle;            end          StIdle:begin                BitCnt <= 0;                                 BitCellCnt <= 0;                done <= 1;                if (iEnStr) begin                    buffer <= load(parity);                    done <= 0;                end            end          StWait:begin                if (BitCellCnt == lpBitCellWidth)                    BitCellCnt <= 0;                else                    BitCellCnt <= BitCellCnt + 1;            end                  StShift:begin                buffer <= {1'b1, buffer[lpBufferWidth-1:1]};                if (BitCnt == lpPacketWidth-1) begin                    BitCnt <= 0;                    done <= 1;                end else                    BitCnt <= BitCnt + 1;            end      endcase    end  function [lpBufferWidth - 1:0] load (input integer parity);  begin    if (parity) load = {^data, data, 1'b0};    else load = {data, 1'b0};  end  endfunction``
Example 2:
``  reg [1:0] state;  localparam StIdle  = 2'b00;  localparam StWait  = 2'b01;  localparam StShift = 2'b10;  localparam lpBufferWidth = 1 + pDataWidth + pParity;  reg [lpBufferWidth-1:0] buffer;  localparam lpPacketWidth = lpBufferWidth + pStopBits;  reg [\$clog2(lpPacketWidth)-1:0] BitCnt;  reg [15:0] BitCellCnt;  reg done = 0;  assign oDone = done & ~en;  always @(posedge rst, posedge clk)    if (rst) begin          BitCnt <= 0;          BitCellCnt <= 0;          buffer <= {lpBufferWidth{1'b1}};          done <= 1;          state <= StIdle;      end    else begin      case(state)        StIdle:begin              BitCnt     <= 0;                       BitCellCnt <= 0;              done       <= 1;              if (en) begin                  buffer     <= load(pParity);                  done       <= 0;                  state      <= StWait;              end          end        StWait:begin              if (BitCellCnt == lpBitCellWidth) begin                  BitCellCnt <= 0;                  state      <= StShift;              end else                  BitCellCnt <= BitCellCnt + 1;          end        StShift:begin              buffer <= {1'b1, buffer[lpBufferWidth-1:1]};              if (BitCnt == lpPacketWidth-1) begin                  BitCnt <= 0;                  done <= 1;                  state <= StIdle;              end else begin                  BitCnt <= BitCnt + 1;                  state  <= StWait;              end          end        default: begin              state <= StIdle;          end      endcase    end    function [lpBufferWidth - 1:0] load (input integer parity);  begin    if (parity) load = {^iData, iData, 1'b0};    else load = {iData, 1'b0};  end  endfunction``
``module fsm(  input   wire    clock       ,  input   wire    reset       ,  input   wire    request_1   ,  input   wire    request_2   ,  output  reg     flag_1      ,  output  reg     flag_2) ;parameter idle = 3'b001 , ack_1 = 3'b010 , ack_2 = 3'b100 ; // "one hot" encoding of statesreg [2:0] state ;always @ ( posedge clock )begin  if ( reset == 1'b1 ) begin    state   <= idle ;    flag_1  <= 0    ;    flag_2  <= 0    ;  end  else    case ( state )      idle :        if (request_1 == 1'b1) begin          state   <= ack_1 ;          flag_1  <= 1    ;        end else if ( request_2 == 1'b1 ) begin          flag_2  <= 1    ;          state   <= ack_2 ;        end else begin          state <= idle ;        end      ack_1 :        if ( request_1 == 1'b1 ) begin          state <= ack_1 ;        end        else        begin          flag_1  <= 0    ;          state   <= idle ;        end      ack_2 :        if ( request_2 == 1'b1 )        begin          state <= ack_2 ;        end        else        begin          flag_2  <= 0    ;          state   <= idle ;        end      default :        state <= idle ;    endcaseend``