序列检测(FSM状态机)

序列产生和检测(FSM状态机)

提示:FSM有限状态机,是FPGA和数字IC相关岗位必须要掌握的知识点,在笔试和面试中都非常常见。



前言

笔试题目:
一、了解状态机:什么是摩尔型状态机,什么是米利型状态机,两者的区别是什么?一段式、二段式、三段式状态机的区别?

二、使用状态机产生序列“1101_0110”,串行循环输出该序列;

三、使用状态机检测“1101”,串行输入的测试序列为“11101101011010”,输出信号为valid有效信号,检测到时输出高,否则为低,考虑序列叠加情况,比如“1101101”,则有两个“1101”,即:

11101101011010,在第5个时钟检测到序列,下一个时钟输出高电平;
11101101011010,在第8个时钟检测到序列,下一个时钟输出高电平;
11101101011010,在第13个时钟检测到序列,下一个时钟输出高电平;

给出WORD或PDF版本的报告,包括但不限于文字说明、代码、仿真测试图等。


一、状态机基本概念

状态机状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按预先设定的状态进行转移,是协调相关动作、完成特定操作的控制中心、有限状态机称FSM,主要分为两类:

  1. Moore状态机:输出只和状态有关即只取决当前状态,与输入无关;
  2. Mealy状态机:输出不仅和状态有关即不仅取决当前状态,而且和输入有关;

重点:实现相同的功能时,Mealy型比Moore型节省一个状态,Mealy型比Moore型超前一个时钟周期。

  1. 一段式:一个always块,既描述状态转移,又描述状态的输入输出,当前状态用寄存器输出。
  2. 二段式:两个always块,时序逻辑和组合逻辑分开,一个always块采用同步时序描述状态转移;另一个采用组合逻辑判断状态转移条件,描述状态转移规律及输出,当前状态用组合逻辑输出,可能出现竞争冒险,产生毛刺,而且不利于约束。
  3. 三段式:三个always块,一个always块采用同步时序描述状态转移;一个采用组合逻辑判断状态转移条件,描述状态转移规律;第三个使用同步时序描述状态输出,寄存器输出。

二、使用状态机产生序列“1101_0110”,串行循环输出该序列

1.引入基础笔试题

  1. 欲产生序列信号1101_0111,则至少需要 ______级触发器?

    8bit的状态可以用2^3=8 来表示,至少需3级触发器。

  2. 欲产生序列信号1101_0111,如果用移位寄存器,则至少需要 ______级触发器?

    需要5级触发器。11010111左移位循环举例:
    4级:1101–1010—0101—1011—0111—11111111—1110—1101,出现重复,不可以
    5级:11010—10101—01011—10111—11111—11110—11101—11010,没有重复,可以。

2.FSM产生序列信号

循环移位产生序列信号11010110代码如下(示例):

module  FSM2
(
   input  wire  sys_clk     ,
   input  wire  sys_rst_n   ,
   output reg   data_1 ,
   output wire   data       
);

reg [7:0] data_reg = 8'b1101_0110 ;

always @ ( posedge sys_clk or negedge sys_rst_n ) 
 if( !sys_rst_n ) 
  data_reg <= 8'b1101_0110;
 else  
  data_reg <= {
    
    data_reg[6:0],data_reg[7]};//位拼接符号实现循环移位 
   
assign  data = data_reg[7];//阻塞赋值(=),右侧有变化就立即变化
//非阻塞赋值(<=),右侧有变化,下一个时钟沿变化
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        data_1 <= 1'b0 ;
    else 
        data_1 <= data_reg[7] ;
endmodule

sim仿真代码(示例):

`timescale 1ns/1ns
module tb_FSM2();
  reg  sys_clk   ;
  reg  sys_rst_n ;
  wire data_1   ;
  wire data;

initial begin
    sys_clk = 1'b0  ;
    sys_rst_n <= 1'b0;
    #30
    sys_rst_n <= 1'b1;
    #800
    $stop;
    end
    
always#10 sys_clk = ~sys_clk;
  
FSM2 FSM2_inst
(
   .sys_clk   (sys_clk  )  ,
   .sys_rst_n (sys_rst_n)  ,
   .data_1    (data_1   )   ,  
   . data     ( data    )  
);
endmodule

在这里插入图片描述


三、FSM序列检测序列“1101”

  • IDEL:初始状态,检测到1则去S1(1),否则保持IDEL;
  • S1 (1): 检测到1则来到S2(11),否则回到IDEL;
  • S2 (11): 检测到0则来到S3(110),否则保持S2;
  • S3 (110): 检测到1则来到S4(1101),否则回到IDEL;
  • S4 (1101):检测到1则来到S2(11),否则回到IDEL。

使用Moore状态机最终输出和输入无关,只要S4有输入就输出1,故采用Moore型三段式FSM有限状态机。

FSM检测1101序列(示例):

module  FSM
(
   input  wire  sys_clk     ,
   input  wire  sys_rst_n   ,
   input  wire  data_in           ,
   output reg   data_valid       
);

parameter   IDEL = 5'b00001 ,
            S1   = 5'b00010 ,
            S2   = 5'b00100 ,
            S3   = 5'b01000 ,
            S4   = 5'b10000 ;

reg[4:0] current_state  ;
reg[4:0] next_state     ;
//第一段同步时序逻辑,描述状态切换
  always@(posedge sys_clk)
      if(!sys_rst_n)
          current_state <= IDEL   ;
      else
          current_state <=  next_state ;
//第二段组合逻辑,判断状态转移条件和规律.这里=和<=没区别
    always@(*)
        if(!sys_rst_n)
            next_state <= IDEL  ;
        else 
            case(current_state)
                IDEL    :if(data_in == 1)   next_state <= S1; else next_state <= IDEL;
                S1      :if(data_in == 1)   next_state <= S2; else next_state <= IDEL;
                S2      :if(data_in == 0)   next_state <= S3; else next_state <= S2  ;
                S3      :if(data_in == 1)   next_state <= S4; else next_state <= IDEL;
                S4      :if(data_in == 1)   next_state <= S2; else next_state <= IDEL;
                default : next_state <= IDEL  ;
            endcase
//第三段同步时序逻辑,描述状态输出,Moore型输出:只要S4有输入就输出1
    always@(posedge sys_clk)
        if(!sys_rst_n)
            data_valid <= 1'b0;
        else 
            case(next_state)
                S4      :data_valid <= 1'b1;
                default :data_valid <= 1'b0;
            endcase
endmodule

在这里插入图片描述

sim仿真代码,串行输入的测试序列“11101101011010”,状态机检测“1101”,(示例):

`timescale 1ns/1ns
module tb_FSM();
  reg  sys_clk   ;
  reg  sys_rst_n ;
  reg  data_in   ;
  wire data_valid;

initial begin
    sys_clk = 1'b0  ;
    sys_rst_n <= 1'b0;
    data_in <= 1'b0 ;
    #30
    sys_rst_n <= 1'b1;
    #30
    data_in <= 1'b1 ; #20;//延迟是一个周期
    data_in <= 1'b1 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b0 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b0 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b0 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b0 ; #20;
    data_in <= 1'b1 ; #20;
    data_in <= 1'b0 ; #20; 
    #150
    $stop;
    end
    
always#10 sys_clk = ~sys_clk;
  
FSM  FSM_inst
(
   .sys_clk   (sys_clk   ) ,
   .sys_rst_n (sys_rst_n ) ,
   .data_in   (data_in   ) ,
   .data_valid(data_valid) 
);
endmodule

在这里插入图片描述


总结

  • 在序列产生处:通过位拼接符号实现循环移位
  • 在序列产生处:阻塞赋值和非阻塞赋值的区别,两个信号都进行了对比
  • 在序列检测处:三段式状态机写代码的特点
  • 在序列检测处:第三段时,Moore状态机和Mealy状态机输出的区别

刚开始仿真效果没有对上,最后发现:data_in输入之后的延迟没有和时钟周期同步,不是20ns。

猜你喜欢

转载自blog.csdn.net/Lethe_01/article/details/124813845