(1)了解状态机:什么是摩尔型状态机,什么是米利型状态机,两者的区别是什么?一段式、二段式、三段式状态机的区别?
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:
Mealy型:输出信号不仅取决于当前状态,还取决于输入;
Moore型:输出信号只取决于当前状态;
实现相同的功能时,Mealy型比Moore型能节省一个状态(大部分情况下能够节省一个触发器资源,其余情况下使用的资源相同,视状态数和状态编码方式决定),Mealy型比Moore型输出超前一个时钟周期。
一段式:一个always块,既描述状态转移,又描述状态的输入输出,当前状态用寄存器输出。一段式写法简单,但是不利于维护,状态扩展麻烦,状态复杂时易出错,不推荐;
二段式:两个always块,时序逻辑与组合逻辑分开,一个always块采用同步时序描述状态转移;另一个always块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出,当前状态用组合逻辑输出,可能出现竞争冒险,产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计;
三段式:三个always块,一个always模块采用同步时序描述状态转移;一个always采用组合逻辑判断状态转移条件,描述状态转移规律;第三个always块使用同步时序描述状态输出,寄存器输出。
三段式与二段式相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出。
(2)使用状态机产生序列“11010110”,串行循环输出该序列;
(3)使用状态机检测“1101”,串行输入的测试序列为“11101101011010”,输出信号为valid有效信号,检测到时输出高,否则为低,考虑序列叠加情况,比如“1101101”,则有两个“1101”,
根据待检测的序列“1101”确定状态,其中:
S1为检测到第1个有效位“1”;
S2为检测到2个有效位“11”;
S3为检测到3个有效位“110”;
S4位检测到4个有效位“1101”;
IDLE为其他状态;
IDLE:初始状态,除S1~S4外的其他所有状态
S1:1, 来1则到S2(11),否则回到IDLE;
S2:11, 来0则到S3(110),否则保持S2(11);
S3:110, 来1则到S4(1101),否则回到IDLE;
S4:1101, 来1则到S2(11),否则回到IDLE;
module FSM_SequDetection_1( clk, rst_n, data_in, data_valid ); input clk; input rst_n; input data_in; output reg data_valid; //定义状态,这里采用的独热码(One-Hot),FPGA中推荐用独热码和格雷码(Gray) //状态较少时(4-24个状态)用独热码效果好,状态多时格雷码(状态数大于24)效果好 parameter IDLE = 5'b00001; parameter S1 = 5'b00010; parameter S2 = 5'b00100; parameter S3 = 5'b01000; parameter S4 = 5'b10000; reg [4:0] current_state; //现态 reg [4:0] next_state; //次态 //三段式FSM,第一段,同步时序逻辑,描述状态切换,这里的写法固定 always @ ( posedge clk ) begin if(!rst_n ) begin current_state<= IDLE; end elsebegin current_state<= next_state; end end //三段式FSM,第二段,组合逻辑,判断状态转移条件,描述状态转移规律 //这里面用"="赋值和用"<="没区别 always @ (*) begin if(!rst_n ) begin next_state<= IDLE; end elsebegin case(current_state ) IDLE: begin if(data_in == 1 ) next_state<= S1; else next_state<= IDLE; end S1 : begin if(data_in == 1 ) next_state<= S2; else next_state<= IDLE; end S2 : begin if(data_in == 0 ) next_state<= S3; else next_state<= S2; end S3 : begin if(data_in == 1 ) next_state<= S4; else next_state<= IDLE; end S4 : begin if(data_in == 1 ) next_state<= S2; else next_state<= IDLE; end default : begin next_state<= IDLE; end endcase end end //三段式FSM,第三段,同步时序逻辑,描述状态输出,摩尔型输出 always @ ( posedge clk ) begin if(!rst_n ) begin data_valid<= 1'b0; end elsebegin case(next_state ) S4 : data_valid <= 1'b1; default : data_valid <= 1'b0; endcase end end endmodule
2.检测序列10110,用计数计其出现的次数。
module seq_dec( input clk, input rst_n, input din, output dout ); reg [7:0] cnt; //计满足10110序列的次数 reg [5:0] P_state;//当前状态 reg [5:0] N_state;//下一个状态 parameter S0=6'b000001;//start parameter s1=6'b000010;//1 parameter s2=6'b000100;//10 parameter s3=6'b001000;//101 parameter s4=6'b010000;//1011 parameter s5=6'b100000;//10110 always @(posedge clk or negedge rst_n) if(!rst_n) P_state <= 6'b0; else P_state <= N_state; always @(*)begin if(!rst) N_state = s0; else begin case(P_state) s0:if(din==1) N_state = s1; s1:if(din==0) N_state = s2; s2:if(din==1) N_state = s3; else N_state = s0; s3:if(din==1) N_state = s4; else N_state = s0; s4:if(din==0) N_state = s5; else N_state = s1; s5:if(din==1) N_state = s3; else N_state = s0; default: N_state = s0; endcase end end assign dout = (P_state==s5); always @(posedge clk or negedge rst_n) if(!rst_n) cnt <= 8'b0; else if(dout == 1) cnt <= cnt + 1'b1; endmodule
3.序列检测,每检测到一组“11011”,然后输出一个高电平。
module FSM_test( input clk, input rst_n, input d_in, output d_out ); /* parameter S0 = 5'b000000, S1 = 5'b000001, S2 = 5'b000011, S3 = 5'b000010, S4 = 5'b000110, S5 = 5'b000111; */ parameter S0 = 5'b00000, S1 = 5'b00001, S2 = 5'b00010, S3 = 5'b00100, S4 = 5'b01000, S5 = 5'b10000; /* parameter S0 = 5'd0, S1 = 5'd1, S2 = 5'd2, S3 = 5'd3, S4 = 5'd4, S5 = 5'd5; */ reg r_d_out; reg [4:0] cs,ns; always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin cs <= S0; end else begin cs <= ns; end end always@(*) begin ns = 5'dx; case(cs) S0: begin if(d_in == 1'b1) ns = S1; else ns = S0; end S1: begin if(d_in == 1'b1) ns = S2; else ns = S0; end S2: begin if(d_in == 1'b1) ns = S2; else ns = S3; end S3: begin if(d_in == 1'b1) ns = S4; else ns = S0; end S4: begin if(d_in == 1'b1) ns = S5; else ns = S0; end S5: begin if(d_in == 1'b1) ns = S2; else ns = S3; end default: ns = S0; endcase end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin r_d_out <= 1'b0; end else if(cs == S5)begin r_d_out <= 1'b1; end else begin r_d_out <= 1'b0; end end assign d_out = r_d_out; endmodule