狀態機、序列檢測器


(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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM