(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