概述
Verilog HDL 的语句块都是并行执行的, 但是在很多情况下,我们希望执行按照顺序的方式进行,而状态机就可以很好的实现顺序执行。
状态机组成要素:状态、初态、转移条件、输入符号集、输出符号集
状态机工作要素:现态、次态(下一状态)、输入、输出
有限状态机(Finite State Machine, FSM) 又简称为状态机, 是我们用Verilog HDL 描述数字电路的重要组成方式。状态机分为 mealy 型和 moore 型,其中 mealy 型指的是输出不仅与当前状态有关,还与输入有关,如下面举例的自动售卖机,输出饮料与否不仅与当前状态(你已经投入多少钱了)有关 ,还与输入(当前时刻你是否投入钱)有关。moore 型指的是输出只与现态有关。
我们使用状态机描述一个简单的自动售货机,该售货机中的商品 3 元一件,每次投币只能投入1 元。
就着这张图还得补充说明一点,就是状态数的确定。状态有0元、1元、2元三种,为什么没有三元呢?三元的时候就类似于钟表的十二点,和0点是一个时刻。在三元这个’状态‘下,输出1,然后等待下一个状态1元,单从状态转移来看,不考虑输出,’状态3元‘和状态0元一样都是等待状态1元。
同样的例子,密码锁的例子,密码是321三位,状态也是三种。
其实上述说法不正确,这里用的mealy型状态机,所以’状态3元‘和状态0元是可以认为1个状态,如果用moore型状态机,输出判定时不看输入,那么状态3元和状态0元就不能看作一个状态了。但是,习惯上对于这道题,还是习惯用3状态的mealy型状态机。
module zhuangtaiji(
input clk,
input rst_n,
input wire money,
output reg drink
);
parameter INIT = 3'b001;
parameter STATE1 = 3'b010;
parameter STATE2 = 3'b100;
reg [2:0] state;
always@(posedge clk or negedge rst_n) begin
if (rst_n==0)
state = INIT;
else case(state)
INIT:if(money==1'b1)state = STATE1;
else state = INIT;
STATE1:if(money==1'b1)state = STATE2;
else state = STATE1;
STATE2:if(money==1'b1)state = INIT;
else state = STATE2;
default:state = INIT;
endcase
end
always@(posedge clk or negedge rst_n) begin
if (rst_n==0) drink=0;
else if(state == STATE2&&money==1'b1)
drink=1;
else drink=0;
end
endmodule
tb文件
`timescale 1ns / 1ps
module tb;
// Inputs
reg clk;
reg rst_n;
reg money;
// Outputs
wire drink;
// Instantiate the Unit Under Test (UUT)
zhuangtaiji uut (
.clk(clk),
.rst_n(rst_n),
.money(money),
.drink(drink)
);
initial begin
// Initialize Inputs
clk = 1;
rst_n <= 0;
money <= 0;
// Wait 100 ns for global reset to finish
#100 rst_n<= 1;
// Add stimulus here
end
always #10 clk=~clk;
always #20 money={$random};
endmodule
上述状态机表示为两段式。若改为三段式,则一个always块中只实现状态的转移,设置一个now_state,next_state,该always块中只实现now_state<=next_state。第二个always块中实现next_state的判定,即什么条件下next_state是什么。第三个always块中实现输出。
第一段状态,时序电路的always模块,用同步电路描述状态跳转的过程,这样可利用触发器消除不稳定状态。
第二段状态,组合逻辑always模块,用以描述状态转移的判断条件,利用组合逻辑实现,达到立即判断的效果,在下一时钟边沿同步变化
第三段状态,时序电路always模块,用以描述每一段状态的结果输出,使用时序电路实现,消除不稳定状态的变化,达到同步跳转的效果
三段分别是:
状态计算逻辑
输出逻辑
状态寄存器
`timescale 1ns / 1ps
module zhuangtaiji(
input clk,
input rst_n,
input wire money,
output reg drink
);
parameter INIT = 3'b001;
parameter STATE1 = 3'b010;
parameter STATE2 = 3'b100;
reg [2:0] now_state,next_state;
always@(posedge clk or negedge rst_n)
if (rst_n==0) now_state<=INIT;
else now_state <= next_state;
always@(*) begin
if (rst_n==0)
next_state = INIT;
else case(now_state)
INIT:if(money==1'b1)next_state = STATE1;
else next_state = INIT;
STATE1:if(money==1'b1)next_state = STATE2;
else next_state = STATE1;
STATE2:if(money==1'b1)next_state = INIT;
else next_state = STATE2;
default:next_state = INIT;
endcase
end
always@(posedge clk or negedge rst_n) begin
if (rst_n==0) drink=0;
else if(now_state == STATE2&&money==1'b1)
drink=1;
else drink=0;
end
endmodule
上述三段式状态机,第三段描述输出时,使用的是时序逻辑电路,但是看下图貌似是组合逻辑电路。其实从时序逻辑的基本类型触发用组合逻辑即可,而且仿真也可以。
第三段改为:
always@(*) begin
if (rst_n==0) drink=0;
else if(now_state == STATE2&&money==1'b1)
drink=1;
else drink=0;
end
但是为什么还要用时序逻辑呢?原因是为了消除毛刺,由于传输延迟的不一致,now_state == STATE2&&money==1’b1这两个条件可能不同时到达,所以用时序逻辑,可以消除毛刺。
底下说的是最基本的,可以在此基础上更改。
具体毛刺消除可以看竞争冒险
2020.8.1补充
三段状态机的实现其实是基于 基于D触发器的时序逻辑电路的基本类型 的。
两段状态机其实就是组合逻辑电路1和D触发器合并写到一起的结果。
密码锁栗子:
为仿真方便,我把密码改为了321.
几个第一遍做题中中出现的问题:
1.状态转移图画的还不是很流畅,应该做法从state0开始,什么条件进入state1,什么条件返回state0.然后进入state1,什么条件进入state2,什么条件返回state0(state1)…
2.重复放出这张图
注意在时序逻辑中,是next_state赋值给current_state,毕竟在时序逻辑中是真实度过时间了嘛,所以上一时刻的次态就成为了现在时刻的现态。
3.组合逻辑的next_state确定时,还是忘了default。还有这个题中,在进入状态2后,不管你的输入是什么都将会进入状态0.然后你会发现,状态2可以和default合并。
还有一点确定的是,在case分支有多条语句时,可以不用begin-end.
module aaa(input clk,input rst_n,input [3:0] din,output reg out);
reg [1:0] next_state,current_state;
always@(posedge clk or negedge rst_n)
if(!rst_n) current_state <= 2'b00;
else current_state <= next_state;
always@(*) begin
if(~rst_n) next_state =2'b00;
else case (current_state)
2'b00:if(din == 2'd3) next_state =2'b01;
else next_state <=2'b00;
2'b01:if(din == 2'd2) next_state =2'b10;
else next_state =2'b00;
default: next_state =2'b00;
endcase
end
always@(*) begin
if(!rst_n) out = 0;
else if(current_state == 2'b10 && din == 4'd1 )
out = 1'b1;
else out = 1'b0;
end
endmodule
tb文件
`timescale 1ns / 1ps
module tb;
reg clk,rst_n;
reg [3:0] din;
wire out;
aaa aaa( clk, rst_n, din, out);
initial begin
clk = 0;
din = 0;
forever
#10 clk = ~clk;
end
initial begin
rst_n = 1;
#70 rst_n = 0;
#50 rst_n = 1;
#1000 $finfish;
end
always @(posedge clk)
din = din - 1;
endmodule
人家的做题中的画电路图的步骤
最后
以上就是小巧烧鹅为你收集整理的FPGA之状态机--基于D触发器的时序逻辑基本类型的全部内容,希望文章能够帮你解决FPGA之状态机--基于D触发器的时序逻辑基本类型所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复