状态机中主要包含三个对象:
-现态 current state CS
-次态 next state NS
-输出逻辑 out logic OL
描述方式:
①三段式描述:CS、NS、OL各自采用一个always语句块描述。
②两段式描述:CS+NS采用一个always语句块描述,OL采用一个always语句块描述。or CS采用一个always语句块描述,NS+OL采用一个always语句块描述。
③单段式描述:CS+NS+OL都放在一个always语句块描述。
应该选择哪一种状态机 ?
- 三段式状态机与二段式状态机相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出,解决了毛刺问题。实际应用中三段式状态机使用最多,因为三段式状态机将组合逻辑和时序分开,有利于综合器分析优 化以及程序的维护;并且三段式状态机将状态转移与状态输出分开,使代码看上去更加清晰易懂,提高了代码的可读性,推荐大家使用三段式状态机。
- 二段式状态机将同步时序和组合逻辑分别放到不同的always模块中实现,这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。但是其当前状态的输出用组合逻辑实现,组合逻辑很容易产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计。
- 一段式状态机写法不够模块化 ,且过于臃肿不利于维护,及布局布线。
Moore机和Mealy机区分:
- Moore机:输出由当前状态决定。
Moore机的模型如下图所示,对比Mealy机的模型可以发现,其区别在于Mealy机的输出由当前状态和输入条件决定的,而Moore状态机的输出只取决于当前状态。
- Mealy机:输出由当前状态和输入共同决定。
Mealy机的模型如下图所示,模型中第一个方框是指产生下一状态的组合逻辑 F,F 是当前状态和输 入信号的函数,状态是否改变、如何改变,取决于组合逻辑 F 的输出;第二框图是指状态寄存器,其由一 组触发器组成,用来记忆状态机当前所处的状态,状态的改变只发生在时钟的跳边沿;第三个框图是指产生输出的组合逻辑 G,状态机的输出是由输出组合逻辑 G 提供的,G 也是当前状态和输入信号的函数。
使用Quartus II 查看状态机:
第一,编译并综合。
第二,tools -> netlist viewers -> RTL viewer
第三,找到状态机,双击。
第四,完成。
eg1:可乐售卖机:投入3元出一瓶可乐,按复位键退钱
moore型:
①三段式:
//moore三段式状态机 采用独热码编码模式
module cola_3_moore(
input clk,
input rst,
input money,
output reg cola
);
/*定义寄存器现态、次态*/
reg[3:0]state,next_state;
/*定义状态编码*/
localparam IDLE = 4'b0001,
ONE = 4'b0010,
TWO = 4'b0100,
THREE = 4'b1000;
/*============状态机第一段:同步时序描述状态转移==============*/
always @(posedge clk , negedge rst) begin
if(!rst) state <= IDLE;
else state <= next_state;
end
/*============状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律============*/
always @(state , money) begin
case (state)
IDLE:begin
if(money) next_state<=ONE;
else next_state<=IDLE;
end
ONE:begin
if(money) next_state<=TWO;
else next_state<=ONE;
end
TWO:begin
if(money) next_state<=THREE;
else next_state<=TWO;
end
THREE:begin
if(money) next_state<=ONE;
else next_state<=IDLE;
end
default: begin/*默认状态同IDLE*/
if(money) next_state<=ONE;
else next_state<=IDLE;
end
endcase
end
/*============--状态机第三段:时序逻辑描述输出============*/
always @(posedge clk ,negedge rst) begin
if(!rst)
cola <= 1'b0;
else begin
case(state)
IDLE: cola <=1'b0;
ONE: cola <=1'b0;
TWO: cola <=1'b0;
THREE: cola <=1'b1;
default:cola <=1'b0;
endcase
end
end
endmodule
②两段式:
//moore两段式状态机 采用独热码编码模式
module cola_2_moore(
input clk,
input rst,
input money,
output reg cola
);
/*定义寄存器现态、次态*/
reg[3:0]state,next_state;
/*定义状态编码*/
localparam IDLE = 4'b0001,
ONE = 4'b0010,
TWO = 4'b0100,
THREE = 4'b1000;
/*============状态机第一段:同步时序描述状态转移==============*/
always @(posedge clk , negedge rst) begin
if(!rst) state <= IDLE;
else state <= next_state;
end
/*============状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律及输出============*/
always @(state , money) begin
case (state)
IDLE:begin
if(money) begin
next_state<=ONE;
cola <=1'b0;
end
else begin
next_state<=IDLE;
cola <=1'b0;
end
end
ONE:begin
if(money) begin
next_state<=TWO;
cola <=1'b0;
end
else begin
next_state<=ONE;
cola <=1'b0;
end
end
TWO:begin
if(money) begin
next_state<=THREE;
cola <=1'b0;
end
else begin next_state<=TWO;
cola <=1'b0;
end
end
THREE:begin
if(money) begin
next_state<=ONE;
cola <=1'b1;
end
else begin
next_state<=IDLE;
cola <=1'b1;
end
end
default: begin
if(money) begin
next_state<=ONE;
cola <=1'b0;
end
else begin
next_state<=IDLE;
cola <=1'b0;
end
end
endcase
end
endmodule
mealy型:
①三段式:
//mealy三段式状态机 采用独热码编码模式
module cola_3_mealy(
input clk,
input rst,
input money,
output reg cola
);
/*定义寄存器现态、次态*/
reg[2:0]state,next_state;
/*定义状态编码*/
localparam IDLE = 3'b001,
ONE = 3'b010,
TWO = 3'b100;
/*============状态机第一段:同步时序描述状态转移==============*/
always @(posedge clk , negedge rst) begin
if(!rst) state <= IDLE;
else state <= next_state;
end
/*============状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律============*/
always @(state , money) begin
case (state)
IDLE:begin
if(money) next_state<=ONE;
else next_state<=IDLE;
end
ONE:begin
if(money) next_state<=TWO;
else next_state<=ONE;
end
TWO:begin
if(money) next_state<=IDLE;
else next_state<=TWO;
end
default: begin/*默认状态同IDLE*/
if(money) next_state<=ONE;
else next_state<=IDLE;
end
endcase
end
/*============--状态机第三段:时序逻辑描述输出============*/
always @(posedge clk ,negedge rst) begin
if(!rst)
cola <= 1'b0;
else begin
case(state)
IDLE: cola <=1'b0;
ONE: cola <=1'b0;
TWO:begin
if(money) cola <=1'b1;
else cola <=1'b0;
end
default:cola <=1'b0;
endcase
end
end
endmodule
②两段式:
//mealy两段式状态机 采用独热码编码模式
module cola_2_mealy(
input clk,
input rst,
input money,
output reg cola
);
/*定义寄存器现态、次态*/
reg[2:0]state,next_state;
/*定义状态编码*/
localparam IDLE = 3'b001,
ONE = 3'b010,
TWO = 3'b100;
/*============状态机第一段:同步时序描述状态转移==============*/
always @(posedge clk , negedge rst) begin
if(!rst) state <= IDLE;
else state <= next_state;
end
/*============状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出============*/
always @(state , money) begin
case (state)
IDLE:begin
if(money) begin
next_state<=ONE;
cola <=1'b0;
end
else begin
next_state<=IDLE;
cola <=1'b0;
end
end
ONE:begin
if(money) begin
next_state<=TWO;
cola <=1'b0;
end
else begin
next_state<=ONE;
cola <=1'b0;
end
end
TWO:begin
if(money) begin
next_state<=IDLE;
if(money) cola <=1'b1;
end
else begin
next_state<=TWO;
cola <=1'b0;
end
end
default:begin
if(money) begin
next_state<=ONE;
cola <=1'b0;
end
else begin
next_state<=IDLE;
cola <=1'b0;
end
end
endcase
end
endmodule
eg2:以“101序列检测器”为例:
可重叠和不可重叠区分:
- 可重叠的序列检测器检测到一个目标串后可以不用回到初始状态,该目标串的元素的可作为下一个目标串的子串继续进行判断。
0 1 1 0 1 0 1 0 1 1 1 0 - 不可重叠的序列检测器一次检测完成后必须回到初始状态。
0 1 1 0 1 0 1 0 11 1 0
状态分析及转移图:
可重叠moore机:
①三段式
//moore 三段式 可重叠 101序列检测
module moore_101_seq_3(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [3:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =4'b0001,
S1 =4'b0010,
S2 =4'b0100,
S3 =4'b1000;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:if(i==1)next_state <= S1;
else next_state <= IDLE;
S1:if(i==0)next_state <= S2;
else next_state <= S1;
S2:if(i==1)next_state <= S3;
else next_state <= IDLE;
S3:if(i==0)next_state <= S2;
else next_state <= S1;
default: if(i==1)next_state <= S1;//与IDLE状态相同
else next_state <= IDLE;
endcase
end
/*===============第三段状态机:时序逻辑定义输出===============*/
always @(posedge clk,negedge rst) begin
case (state)
IDLE: dec_101 <= 1'b0;
S1: dec_101 <= 1'b0;
S2: dec_101 <= 1'b0;
S3: dec_101 <= 1'b1;
default: dec_101 <= 1'b0;
endcase
end
endmodule
②两段式:
//moore 两段式 可重叠 101序列检测
module moore_101_seq_2(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [3:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =4'b0001,
S1 =4'b0010,
S2 =4'b0100,
S3 =4'b1000;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数及输出===============*/
always @(*) begin
case (state)
IDLE:begin
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
S1:begin
dec_101 <= 1'b0;
if(i==0)next_state <= S2;
else next_state <= S1;
end
S2:begin
dec_101 <= 1'b0;
if(i==1)next_state <= S3;
else next_state <= IDLE;
end
S3:begin
dec_101 <= 1'b1;
if(i==0)next_state <= S2;
else next_state <= S1;
end
default: begin
dec_101 <= 1'b0;
if(i==1)next_state <= S1;//与IDLE状态相同
else next_state <= IDLE;
end
endcase
end
endmodule
testbench中状态机名称查看器的编写方法:
让当前状态不以进制01方式显示,而直接显示state名称。
解决思路:在Testbench构造一个reg变量,这个变量显示ASCII值,然后想办法让这个值等于state。这样的话我们就算没办法直接将state用字符显示,但我们可以用字符显示一个与其值一致的变量。
具体步骤:
- 构造一个reg变量state_tb,位宽=状态机状态的字符的最长长度*8(每个字符的ASCII码需要8个bit)。
- 根据状态机的状态对state_tb赋值,赋值内容为状态对应的字符。
moore型FSM testbench:
//testbench 101sequence
`timescale 1ns/1ns
/*==========模块及端口声明==========*/
module tb_moore_101_seq();
reg clk;
reg rst;
reg i;
wire dec_101;
/*==========例化被测试模块==========*/
moore_101_seq_3 U1(
.clk(clk),
.rst(rst),
.i(i),
.dec_101(dec_101)
);
/*==========设置初始化条件==========*/
initial begin
clk = 1'b0;
rst = 1'b0;
i <= 1'b0;
#5 rst = 1'b1;i <= 1'b1;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 i <= 1'b1;
#20 i <= 1'b1;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 rst = 1'b0;
end
/*==========设置时钟==========*/
always #10 clk =~clk;//系统时钟周期20ns
/*==========状态机名称查看器==========*/
//每个字符8位宽,此处最多的THREE=40位宽
reg [39:0]state_name;
reg [39:0]next_state_name;
always @(*) begin
case (U1.state)
4'b0001: state_name <="IDLE";
4'b0010: state_name <="S1";
4'b0100: state_name <="S2";
4'b1000: state_name <="S3";
default: state_name <="IDLE";
endcase
end
always @(*) begin
case (U1.next_state)
4'b0001: next_state_name <="IDLE";
4'b0010: next_state_name <="S1";
4'b0100: next_state_name <="S2";
4'b1000: next_state_name <="S3";
default: next_state_name <="IDLE";
endcase
end
endmodule
(moore 三段式 可重叠 101序列检测)
mealy型FSM testbench:
`timescale 1ns/1ns
module tb_fsm_101_seq_mealy();
//端口声明
reg clk;
reg rst;
reg i;
wire dec_101;
//模块例化
mealy_101_seq_3 U1(
.clk(clk),
.rst(rst),
.i(i),
.dec_101(dec_101)
);
//初始化信号
initial begin
clk = 1'b0;
rst = 1'b0;
i <= 1'b0;
#5 rst = 1'b1;i <= 1'b1;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 i <= 1'b1;
#20 i <= 1'b1;
#20 i <= 1'b1;
#20 i <= 1'b0;
#20 rst = 1'b0;
end
//产生时钟
always #10 clk <= ~clk;
//状态机名称显示器
reg [31:0] state_name;
reg [31:0] next_state_name;
always @(*) begin
case(U1.state)
3'b001:state_name <= "IDLE";
3'b010:state_name <= "S1";
3'b100:state_name <= "S2";
default:state_name <= "IDLE";
endcase
end
always @(*) begin
case(U1.next_state)
3'b001:next_state_name <= "IDLE";
3'b010:next_state_name <= "S1";
3'b100:next_state_name <= "S2";
default:next_state_name <= "IDLE";
endcase
end
endmodule
(mealy 三段式 可重叠 101序列检测)
可重叠mealy机:
①三段式
//mealy 三段式 可重叠 101序列检测
module mealy_101_seq_3(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [2:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =3'b001,
S1 =3'b010,
S2 =3'b100;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:if(i==1)next_state <= S1;
else next_state <= IDLE;
S1:if(i==0)next_state <= S2;
else next_state <= S1;
S2:if(i==1)next_state <= S1;
else next_state <= IDLE;
default: if(i==1)next_state <= S1;//与IDLE状态相同
else next_state <= IDLE;
endcase
end
/*===============第三段状态机:时序逻辑定义输出===============*/
always @(posedge clk,negedge rst) begin
case (state)
IDLE: dec_101 <= 1'b0;
S1: dec_101 <= 1'b0;
S2:begin
if(i==1)dec_101 <= 1'b1;
else dec_101 <= 1'b0;
end
default: dec_101 <= 1'b0;
endcase
end
endmodule
②两段式:
//mealy 两段式 可重叠 101序列检测
module mealy_101_seq_2(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [2:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =3'b001,
S1 =3'b010,
S2 =3'b100;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:begin
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
S1:begin
dec_101 <= 1'b0;
if(i==0)next_state <= S2;
else next_state <= S1;
end
S2:begin
if(i==1)begin
next_state <= S1;
dec_101 <= 1'b1;
end
else begin
dec_101 <= 1'b0;
next_state <= IDLE;
end
end
default: begin//同IDLE状态相同
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
endcase
end
endmodule
不可重叠moore机:
①三段式
//moore 三段式 不可重叠 101序列检测
module moore_101_seq_3_not_overlap(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [3:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =4'b0001,
S1 =4'b0010,
S2 =4'b0100,
S3 =4'b1000;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:if(i==1)next_state <= S1;
else next_state <= IDLE;
S1:if(i==0)next_state <= S2;
else next_state <= S1;
S2:if(i==1)next_state <= S3;
else next_state <= IDLE;
S3:if(i==0)next_state <= IDLE;
else next_state <= S1;
default: if(i==1)next_state <= S1;//与IDLE状态相同
else next_state <= IDLE;
endcase
end
/*===============第三段状态机:时序逻辑定义输出===============*/
always @(posedge clk,negedge rst) begin
case (state)
IDLE: dec_101 <= 1'b0;
S1: dec_101 <= 1'b0;
S2: dec_101 <= 1'b0;
S3: dec_101 <= 1'b1;
default: dec_101 <= 1'b0;
endcase
end
endmodule
②两段式:
//mealy 两段式 不可重叠 101序列检测
module mealy_101_seq_2_not_overlap(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [2:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =3'b001,
S1 =3'b010,
S2 =3'b100;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:begin
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
S1:begin
dec_101 <= 1'b0;
if(i==0)next_state <= S2;
else next_state <= S1;
end
S2:begin
if(i==1)begin
next_state <= IDLE;
dec_101 <= 1'b1;
end
else begin
dec_101 <= 1'b0;
next_state <= IDLE;
end
end
default: begin//同IDLE状态相同
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
endcase
end
endmodule
不可重叠mealy机:
①三段式:
//mealy 三段式 不可重叠 101序列检测
module mealy_101_seq_3_not_overlap(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [2:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =3'b001,
S1 =3'b010,
S2 =3'b100;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:if(i==1)next_state <= S1;
else next_state <= IDLE;
S1:if(i==0)next_state <= S2;
else next_state <= S1;
S2:next_state <= IDLE;
default: if(i==1)next_state <= S1;//与IDLE状态相同
else next_state <= IDLE;
endcase
end
/*===============第三段状态机:时序逻辑定义输出===============*/
always @(posedge clk,negedge rst) begin
case (state)
IDLE: dec_101 <= 1'b0;
S1: dec_101 <= 1'b0;
S2:begin
if(i==1)dec_101 <= 1'b1;
else dec_101 <= 1'b0;
end
default: dec_101 <= 1'b0;
endcase
end
endmodule
②两段式:
//mealy 两段式 不可重叠 101序列检测
module mealy_101_seq_2_not_overlap(
input clk,
input rst,
input i,
output reg dec_101
);
/*===============状态寄存器===============*/
reg [2:0]state,next_state;
/*===============状态参数===============*/
localparam IDLE =3'b001,
S1 =3'b010,
S2 =3'b100;
/*===============第一段状态机:时序逻辑初始化===============*/
always @(posedge clk,negedge rst) begin
if(!rst)
state <= IDLE;
else
state <= next_state;
end
/*===============第二段状态机:组合逻辑定义参数===============*/
always @(*) begin
case (state)
IDLE:begin
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
S1:begin
dec_101 <= 1'b0;
if(i==0)next_state <= S2;
else next_state <= S1;
end
S2:begin
if(i==1)begin
next_state <= IDLE;
dec_101 <= 1'b1;
end
else begin
dec_101 <= 1'b0;
next_state <= IDLE;
end
end
default: begin//同IDLE状态相同
dec_101 <= 1'b0;
if(i==1)next_state <= S1;
else next_state <= IDLE;
end
endcase
end
endmodule
参考文章:
原文链接:https://blog.csdn.net/wuzhikaidetb/article/details/121206908
原文链接:https://blog.csdn.net/wuzhikaidetb/article/details/119421783