0 votes
in Verilog by (200 points)

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

2 Answers

0 votes
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
0 votes
by (300 points)

A common and reliable way to implement a state machine in verilog is using the single always method.
This example will use this method together with a "one hot" encoded state register.

Example :

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 states
reg [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 ;
endcase
end
Hardware Coder Community

© 2022 by Hardware Coder. User contributions are licensed under cc by-sa 4.0 with attribution required. Attribution means a link to the question, answer, user, etc on this site.

This site is owned and operated by Hardware Coder in McKinney, Texas.

Send Us A Message
About Us

By using this site, you agree to the following:

Privacy Policy
Terms and Conditions
DMCA Policy
Earnings Disclaimer
Legal Disclaimer

...