1 状态机原理
Verilog HDL语句块都是并行执行的,若想按照顺序的方式执行语句,则会使用有限状态机,简称为状态机。
状态机的设计分为一段式、二段式和三段式。通常使用两段式状态机和三段式状态机。
1.1 二段式状态机
二段式状态机使用一个时序逻辑进行状态的转移,另一个时序逻辑进行数据的输出,模板如下所示:
//二段式状态机模板
module 模块名(
端口1,
端口2,
...
端口n
)
//用独热码描述状态
localparam 状态1 = n'b0000...0001;
localparam 状态2 = n'b0000...0010;
...
localparam 状态n = n'b1000...0000;
reg [位宽] state; //当前状态
//时序逻辑描述的状态转移
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
state <= 默认状态;
end
else case(state)
状态1: begin
if (状态转移条件) begin
state <= 下一个状态;
end
else begin
state <= state;
end
end
状态2: begin
...
end
...
状态n: begin
...
end
default begin
state = 默认状态;
end
endcase
end
//时序逻辑描述的数据输出
always @(posedge clk or negedge rst_n) begin
数据输出;
end
endmodule
1.2 三段式状态机
三段式状态机将二段式状态机中进行状态转移的时序逻辑分为两个部分,其中一部分用时序逻辑实现状态的存储,另一部分用组合逻辑实现状态的跳转。与二段式状态机相同的是,都用一个时序逻辑进行数据的输出,模板如下所示:
//三段式状态机模板
module 模块名(
端口1,
端口2,
...
端口n
)
//用独热码描述状态
localparam 状态1 = n'b0000...0001;
localparam 状态2 = n'b0000...0010;
...
localparam 状态n = n'b1000...0000;
reg [位宽] curr_state; //当前状态
reg [位宽] next_state; //接下来的状态
//时序逻辑描述实现状态curr_state的存储
always @(posedge clk or posedge rst_n) begin
if (rst_n == 1'b0) begin
curr_state <= 默认状态;
end
else begin
curr_state <= next_state;
end
end
//组合逻辑实现状态next_state的跳转
always @(posedge clk or negedge rst_n) begin
case(curr_state)
状态1: begin
if (状态转移条件) begin
next_state <= 下一个状态;
end
else begin
next_state <= 状态1;
end
end
状态2: begin
...
end
...
状态n: begin
...
end
default begin
next_state = 默认状态;
end
endcase
end
//时序逻辑描述的数据输出
always @(posedge clk or negedge rst_n) begin
数据输出;
end
endmodule
三段式状态机将组合逻辑和时序逻辑分开的好处就是将来在修时序的时候方便插入寄存器。
2 实例:自动售货机
使用状态机描述一个简单的自动售货机,该售货机中的商品3元一件,每次投币只能投入1元。在我们描述状态机之前,一般会先画出对应的状态转移图,该状态转移图如图 1 所示。
根据状态转移图,我们可以得到如下所示的Verilog HDL代码:
2.1 两段式
module fsm(
input wire clk,
input wire rst_n,
input wire pi_money,
output reg po_cola
);
//用独热码描述状态
localparam IDLE = 3'b001;
localparam ONE = 3'b010;
localparam TWO = 3'b100;
//两段式状态机
//状态寄存器(两段式)
reg [2:0] state;
//该always块描述状态转移:state
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
state <= IDLE;
end
else case(state)
IDLE: begin
if (pi_money == 1'b1) begin
state <= ONE;
end
else begin
state <= state;
end
end
ONE: begin
if (pi_money == 1'b1) begin
state <= TWO;
end
else begin
state <= state;
end
end
TWO: begin
if (pi_money == 1'b1) begin
state <= IDLE;
end
else begin
state <= state;
end
end
default: begin
state <= IDLE;
end
endcase
end
//该always快描述数据输出:po_cola
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
po_cola <= 1'b0;
end
else if (state == TWO && pi_money == 1'b1) begin
po_cola <= 1'b1;
end
else begin
po_cola <= 1'b0;
end
end
2.2 三段式
module fsm(
input wire clk,
input wire rst_n,
input wire pi_money,
output reg po_cola
);
//用独热码描述状态
localparam IDLE = 3'b001;
localparam ONE = 3'b010;
localparam TWO = 3'b100;
//三段式寄存器 (将两段式寄存器第一个always块拆分为2个部分,一个部分用时序逻辑,另一个部分用组合逻辑)
//curr_state用时序逻辑实现
reg [2:0] curr_state;
//next_state用组合逻辑实现
reg [2:0] next_state;
//时序逻辑实现状态的存储
always @(posedge clk or posedge rst_n) begin
if (rst_n == 1'b0) begin
curr_state <= IDLE;
end
else begin
curr_state <= next_state;
end
end
//组合逻辑实现状态的跳转
always @(*) begin
case(curr_state)
IDLE: begin
if (pi_money == 1'b1) begin
next_state = ONE;
end
else begin
next_state = IDLE;
end
end
ONE: begin
if (pi_money == 1'b1) begin
next_state = TWO;
end
else begin
next_state = ONE;
end
end
TWO: begin
if (pi_money == 1'b1) begin
next_state = IDLE;
end
else begin
next_state = TWO;
end
end
default: begin
next_state = IDLE;
end
endcase
end
//该always快描述数据输出:po_cola
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
po_cola <= 1'b0;
end
else if (curr_state == TWO && pi_money == 1'b1) begin
po_cola <= 1'b1;
end
else begin
po_cola <= 1'b0;
end
end
标签:状态,...,有限,localparam,时序,状态机,state
From: https://www.cnblogs.com/little55/p/18195874