以序列检测器为例讲解有限状态机的编写
一、根据信号产生方法不同,分为米里型和摩尔型
米里型
摩尔型
米里型的输出不仅与当前状态有关,也随输入信号的变化立即变化,而摩尔型的输出只随时钟边沿变化。
二、状态机的编写过程:
1. 画状态转移图(找准输入,当前状态下某一输入所导致的状态转移,每一个状态的组合逻辑输出)
2. 对多余状态的处理(不可能出现的状态),全部转移到可能出现的状态,注意复位信号
3. 写测试代码
三、状态机编码:
最好选用格雷码和one-hot码
格雷码选用原因:格雷码表示的相邻的两个数字之间跳转时只有一位发生变化。提高电路的稳定性,减少毛刺的产生和减少功耗
格雷码组成规律:随数字增长,每个数第一位为0110循环,第二位为00111100循环,第三位为0000111111110000增长,以此类推。
One-hot码组成规律:有n个状态就用n位二进制表示,所有位中只有一位为1,其他为0。例如四个状态:s0=0001,s1=0010,s2=0100,s3=1000。
One-hot码选用原因:没有组合逻辑,电路速度非常快,可靠性高,从组成规律可以看出其实就是移位寄存器。
格雷码与二进制码的转换
(1)二进制码转换成格雷码
从最右边第一位开始,依次将每一位与左邻一位异或(XOR),作为对应格雷码该位的值,最左边一位不变。
(2)格雷码转换成二进制码
从左边第二位起,将每位与左边一位解码后的值异或(XOR),作为该位解码后的值(最左边一位依然不变)。
四、序列检测器:检测序列10110
1、序列检测10110,最重要的问题是为什么我们选择8个状态,当数据进入序列检测器的时候,只要有一个数字破坏了10110这一序列的顺序(比如我们检测到101,结果下一个是0,不是1,我们就要重新开始)我们就要重新开始测,基于这一思想,假设状态数的位数是M,则2^M>待检测序列的数>
2^(M-1)。
2、状态编码利用格雷码和one hot 编码,状态机相邻状态只有一个比特位有变化,减少电路中毛刺的产生。
3、状态机编写(单过程描述方式),注意状态的跳转以及各个状态所对应的组合逻辑的输出,最后就是多余状态的处理
状态转移图
1module seqdetector(clk,clr,met,rst);
2 parameter s0= 3'b000,//表示初始状态
3 s1= 3'b001,//捕捉到数据1'b1
4 s2= 3'b011,//捕捉到数据2'b10
5 s3= 3'b010,//捕捉到数据3'b101
6 s4= 3'b110,//捕捉到数据4'b1011
7 s5= 3'b111,//捕捉到数据5'b10110
8 s6= 3'b101,//多余状态
9 s7= 3'b100;//多余状态
10 //格雷码编码
11 input clk,clr,rst;
12 output met;
13 reg met;
14 reg[2:0] state;
15 always @(posedge clk,posedge rst)//异步复位,同步复位则为:always @(posedge clk)
16 begin
17 if(rst==1'b1) begin state=s0; end18 else19 begin20 case(state)21 s0: if(clr) begin state<=s1; met=1'b0; end//state<=s1表示下一状态为s1
22 else begin state<=s0; met=1'b0; end//met=1'b0表示在此状态下,23 //状态机组合逻辑应该输出1'b0
24 s1: if(clr) begin state<=s1; met=1'b0; end
25 else begin state<=s2; met=1'b0; end
26
27 s2: if(clr) begin state<=s3; met=1'b0; end
28 else begin state<=s0; met=1'b0; end
29
30 s3: if(clr) begin state<=s4; met=1'b0; end
31 else begin state<=s0; met=1'b0; end
32
33 s4: if(clr) begin state<=s1; met=1'b0; end
34 else begin state<=s5; met=1'b0; end
35
36 s5: if(clr) begin state<=s1; met=1'b1; end
37 else begin state<=s0; met=1'b1; end
38 /*39 s6: if(clr) begin state<=s1; met=1'b0; end40 else begin state<=s0; met=1'b0; end4142 s7: if(clr) begin state<=s1; met=1'b0; end43 else begin state<=s0; met=1'b0; end 44 */
45 default:if(clr) begin state<=s1; met=1'b0; end
46 else begin state<=s0; met=1'b0; end//上面注释部分可与default部分相互替换
47 //若检测到序列不满足10110,则根据接收到的状态跳转到s0和s1,
48 //接收到0则跳转到s0,接收到1则跳转到s1。
49
50 endcase
51 end
52
53
54 end
55
56
57
58endmodule
代码
1`timescale 1ns/1ps
2module seqdetector_tb;
3 reg clk_t,rst_t,clr_t;
4 wire met_t;
5 seqdetector sd(.clk(clk_t),
6 .clr(clr_t),
7 .met(met_t),
8 .rst(rst_t));
9 initial
10 begin
11 clk_t=1'b0;rst_t=1'b0;
12 #1;clr_t=1'b0;
13 #3;rst_t=1'b1;
14 #3;rst_t=1'b0;//记得复位信号要回到0,否则状态机一直被复位
15 #1000;$stop;
16 end
17 always #5 clk_t=~clk_t;
18 always #10 clr_t={$random} %2;//随机产生0和1的序列
19endmodule
测试代码
仿真结果
来看看组合逻辑输出为1的细节部分
细节一
细节二