Article directory
Finite state machines are used when processing relatively complex logic. Different states are set, jump to the corresponding state according to the trigger conditions, and then perform corresponding processing in different states. Finite state machines mainly use always statements and case statements.
Implementation of 1011 state machine
The article Design a state machine for identifying the binary sequence "1011" under Quartus II software is a state machine designed in the Quartus II software to identify the binary sequence "1011". Here, the example is implemented in Vivado. .
The design source code is as follows.
module timing(
input clk,
input rst,
input en,
input in,
output reg out
);
parameter ST0 = 0;
parameter ST1 = 1;
parameter ST2 = 2;
parameter ST3 = 3;
parameter ST4 = 4;
reg [2:0] state;
reg [2:0] next_state;
initial
begin
next_state = ST0;
end
always @ (in or en or state)
begin
case (state)
ST0:
begin
if(en == 1 && in == 1)
next_state = ST1;
else
next_state = ST0;
end
ST1:
begin
if(en == 1 && in == 0)
next_state = ST2;
else if(en == 1 && in == 1)
next_state = ST1;
else
next_state = ST0;
end
ST2:
begin
if(en == 1 && in == 1)
next_state = ST3;
else
next_state = ST0;
end
ST3:
begin
if(en == 1 && in == 1)
next_state = ST4;
else if(en == 1 && in == 0)
next_state = ST2;
else
next_state = ST0;
end
//ST4:
//next_state = ST0;
endcase
end
always @ (posedge clk or negedge rst)
begin
if(!rst)
state <= ST0;
else
state <= next_state;
end
always @ (state or posedge clk)
begin
if(state == ST4)
begin
state = ST1;
out = 1;
end
else
out = 0;
end
endmodule
The simulation test source code is as follows.
module sim_timing();
reg clk;
reg rst;
reg en;
reg in;
wire out;
initial
begin
en = 0;
clk = 0;
rst = 1;
#50
en = 1;
#400
rst = 0;
#50
rst = 1;
end
initial
begin
in = 0;
forever
begin
#20
in = {
$random}%2;
end
end
always #10 clk = ~clk;
timing uut_timing(
.clk(clk),
.rst(rst),
.en(en),
.in(in),
.out(out)
);
endmodule
The simulation output results are shown in the figure below.
As can be seen from the above figure, every time a "1011" sequence is input, the output out is set to 1, and is cleared after one clock cycle. The output result is consistent with expectations.
Shift operation in four states
The following figure shows four states. The initial state is Idle. In this state, it is judged whether the shift start signal shift_start is high. If it is high, it enters the Start state. In the Start state, it delays for several cycles and enters the Run state. Then perform shift processing. If the shift stop signal shift_stop is valid, enter the Stop state, clear the value in the memory and then return to the Idle state.
The output of Mealy finite state machine is not only related to the current state, but also related to the input signal.
The design source code of Mealy finite state machine is as follows.
module timing(
input clk,
input rst,
input in,
input shift_start,
input shift_stop,
output reg[7:0] out
);
parameter Idle = 0;
parameter Start = 1;
parameter Run = 2;
parameter Stop = 3;
reg [1:0] state;
reg [3:0] count;
always @ (posedge clk or negedge rst)
begin
if(!rst)
begin
state <= Idle;
count <= 0;
out <= 0;
end
else
case(state)
Idle:
begin
if(shift_start)
state <= Start;
end
Start:
begin
if(count == 4'd10)
begin
count <= 0;
state <= Run;
end
else
count <= count + 1'b1;
end
Run:
begin
if(shift_stop)
state <= Stop;
else
out <= {
out[6:0],in};
end
Stop:
begin
out <= 0;
state <= Idle;
end
default : state <= Idle;
endcase
end
endmodule
The output of Moore finite state machine is only related to the current state and has nothing to do with the input signal. The input signal only affects the change of state and does not affect the output. For example, the counting signal and output signal in this example.
The design source code of Moore finite state machine is as follows.
module timing(
input clk,
input rst,
input in,
input shift_start,
input shift_stop,
output reg[7:0] out
);
parameter Idle = 0;
parameter Start = 1;
parameter Run = 2;
parameter Stop = 3;
reg [1:0] cur_state;
reg [1:0] next_state;
reg [3:0] count;
always @ (posedge clk or negedge rst)
begin
if(!rst)
cur_state <= Idle;
else
cur_state <= next_state;
end
always@(*)
begin
case(cur_state)
Idle:
begin
if(shift_start)
next_state <= Start;
else
next_state <= Idle;
end
Start:
begin
if(count == 4'd10)
next_state <= Run;
else
next_state <= Start;
end
Run:
begin
if(shift_stop)
next_state <= Stop;
else
next_state <= Run;
end
Stop:
next_state <= Idle;
default : next_state <= Idle;
endcase
end
always@(posedge clk or negedge rst)
begin
if(!rst)
count <= 0;
else if (cur_state == Start)
count <= count + 1'b1;
else
count <= 0;
end
always@(posedge clk or negedge rst)
begin
if(!rst)
out <= 0;
else if (cur_state == Run)
out <= {
out[6:0],in};
else
out <= 0;
end
endmodule
Two ways of writing are used in the above two programs. The first Mealy state machine adopts a one-paragraph writing method. Only one always statement is used in the code, and all state transfers, judgment state transfer conditions, and data output are All in one always statement. The disadvantage of this writing method is that if there are too many states, the entire program will become lengthy. The second is the Moore state machine, which adopts a three-stage writing method. An always statement is used for state transfer, an always statement is used to determine the state transfer condition, and an always statement is also used for data output. The code written in this way is more intuitive. It is clear, and it will not appear cumbersome when there are many states.
The simulation test code for both is the same, as shown below.
module sim_timing();
reg clk;
reg rst;
reg in;
reg shift_start;
reg shift_stop;
wire [7:0] out;
initial
begin
clk = 0;
rst = 0;
in = 0;
#100
rst = 1;
forever
begin
#({
$random}%100)
in = ~in;
end
end
initial
begin
shift_start = 0;
shift_stop = 0;
#200
shift_start = 1;
#500
shift_start = 0;
shift_stop = 1;
#50
shift_stop = 0;
shift_start = 1;
end
always #10 clk = ~clk;
timing uut_timing(
.clk(clk),
.rst(rst),
.in(in),
.shift_start(shift_start),
.shift_stop(shift_stop),
.out(out)
);
endmodule
The simulation output results are shown in the figure below.
As can be seen from the above figure, in the Start state, after counting to 10, it jumps to the Run state and starts the shifting operation. The above picture is the overall simulation process. The shift operation cannot be seen clearly, so the output out is displayed in binary. The enlarged picture is as follows. You can see that when shift_start is valid, the left shift operation is performed correctly.
The above is all the content of finite state machine implementation under Vivado!
Reference:
ZYNQ Development Platform FPGA Tutorial AX7020