我是靠谱客的博主 小巧烧鹅,这篇文章主要介绍FPGA之状态机--基于D触发器的时序逻辑基本类型,现在分享给大家,希望可以做个参考。

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型状态机。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
`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模块,用以描述每一段状态的结果输出,使用时序电路实现,消除不稳定状态的变化,达到同步跳转的效果
三段分别是:
状态计算逻辑
输出逻辑
状态寄存器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
`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

上述三段式状态机,第三段描述输出时,使用的是时序逻辑电路,但是看下图貌似是组合逻辑电路。其实从时序逻辑的基本类型触发用组合逻辑即可,而且仿真也可以。
第三段改为:

复制代码
1
2
3
4
5
6
7
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.

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
`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触发器内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部