FSM是電路設計中很是常見的結構,對於這樣常見的結構的正確輸寫很是重要, 良好的代碼風格對於閱讀理解以及後期維護也很是重要。本文總結了目前常見的兩種輸寫FSM的方法html
FSM目前主要有兩種架構後端
要讓電路順序地執行計算,最簡單的方法就是生成一個counter, 而後根據counter值去執行相應的操做或計算。但這種方法只能用於很是簡單的控制,且很是不容易維護以及後期功能修改。因此實際上你們都會用標準的FSM來實現複雜控制。架構
Moore FSM是目前的主流寫法, 它由三塊組成:編碼
假設輸入爲w_i, 輸出爲z_o, 當輸入連續2個cycle爲高時,則輸出爲1個cycle高spa
下面是state diagram設計
/********************************************** Description : 3 always block for moore fsm (BEST) **********************************************/ module simple_fsm ( clk, rst_n, w_i, z_o ); input clk; input rst_n; input w_i; output z_o; parameter IDLE = 2'b00; parameter S0 = 2'b01; parameter S1 = 2'b10; reg [1:0] curr_state; reg [1:0] next_state; reg z_o; // state reg always@(posedge clk or negedge rst_n) begin if (~rst_n) curr_state <= IDLE; else curr_state <= next_state; end // next state logic always@(*) begin case (curr_state) IDLE : if (w_i) next_state = S0; else next_state = IDLE; S0 : if (w_i) next_state = S1; else next_state = IDLE; S1 : if (w_i) next_state = S1; else next_state = IDLE; default : next_state = IDLE; endcase end // output logic always@(*) begin case (curr_state) IDLE : z_o = 1'b0; S0 : z_o = 1'b0; S1 : z_o = 1'b1; default : z_o = 1'b0; endcase end endmodule
下面是相應的TBcode
/********************************************** Description : testbench for FSM **********************************************/ module simple_fsm_tb; reg clk = 1'b1; reg rst_n = 1'b1; reg w_i = 1'b0; wire z_o; // clk always #10 clk = ~clk; event after_rst; // rst_n initial begin #6; // 6ns rst_n = 1'b0; #30; // 36ns rst_n = 1'b1; ->after_rst; end // w_i initial begin @(after_rst); repeat(2)@(posedge clk); // 60ns w_i <= 1'b1; @(posedge clk); // 80 ns w_i <= 1'b0; @(posedge clk); // 100 ns w_i <= 1'b1; repeat(2)@(posedge clk); // 140 ns w_i <= 1'b0; @(posedge clk); // 160 ns w_i <= 1'b1; repeat(3)@(posedge clk); // 220 ns w_i <= 1'b0; end initial begin $fsdbDumpfile("simple_fsm.fsdb"); $fsdbDumpvars(0, simple_fsm_tb); end simple_fsm u_simple_fsm ( .clk (clk), .rst_n (rst_n), .w_i (w_i), .z_o (z_o) ); endmodule
仿真波形以下:htm
代碼以下:blog
module simple_fsm ( clk, rst_n, w_i, z_o ); input clk; input rst_n; input w_i; output z_o; parameter IDLE = 2'b00; parameter S0 = 2'b01; parameter S1 = 2'b10; reg [1:0] curr_state; reg z_o; // state reg + next state logic always@(posedge clk or negedge rst_n) begin if (~rst_n) curr_state <= IDLE; else case (curr_state) IDLE : if (w_i) curr_state <= S0; else curr_state <= IDLE; S0 : if (w_i) curr_state <= S1; else curr_state <= IDLE; S1 : if (w_i) curr_state <= S1; else curr_state <= IDLE; default : curr_state <= IDLE; endcase end // output logic always@(*) begin case (curr_state) IDLE : z_o = 1'b0; S0 : z_o = 1'b0; S1 : z_o = 1'b1; default : z_o = 1'b0; endcase end endmodule
還有其餘二段式,或者一段式,但都不推薦使用。
從條理上講三段式是最清晰的, 易於理解,便於維護ip
架構以下
默認它的輸出行爲與Moore有點不同,輸出會早一拍
原來Moore FSM須要3個state, 改用Mealy FSM只須要2個State
注意上圖中z_o與w_i有關, 因此上圖在s0是不存在w_i/~z_o的狀態
爲了使輸出與Moore FSM相同,須要打一拍
module simple_fsm ( clk, rst_n, w_i, z_o ); input clk; input rst_n; input w_i; output z_o; parameter IDLE = 2'b00; parameter S0 = 2'b01; reg [1:0] curr_state; reg [1:0] next_state; reg z; reg z_o; // state reg always@(posedge clk or negedge rst_n) begin if (~rst_n) curr_state <= IDLE; else curr_state <= next_state; end // next state logic always@(*) begin case (curr_state) IDLE : if (w_i) next_state = S0; else next_state = IDLE; S0 : if (w_i) next_state = S0; else next_state = IDLE; default : next_state = IDLE; endcase end // output logic always@(*) case (curr_state) IDLE : if (w_i) z = 1'b0; else z = 1'b0; S0 : if (w_i) z = 1'b1; else z = 1'b0; default : z = 1'b0; endcase // mealy output to delay 1 clk for moore always@(posedge clk or negedge rst_n) begin if (~rst_n) z_o <= 1'b0; else z_o <= z; end endmodule
module simple_fsm ( clk, rst_n, w_i, z_o ); input clk; input rst_n; input w_i; output z_o; parameter IDLE = 2'b00; parameter S0 = 2'b01; reg [1:0] curr_state; reg z; reg z_o; // state reg + next state logic always@(posedge clk or negedge rst_n) begin if (~rst_n) curr_state <= IDLE; else case (curr_state) IDLE : if (w_i) curr_state <= S0; else curr_state <= IDLE; S0 : if (w_i) curr_state <= S0; else curr_state <= IDLE; default : curr_state <= IDLE; endcase end // output logic always@(*) begin case (curr_state) IDLE : if (w_i) z = 1'b0; else z = 1'b0; S0 : if (w_i) z = 1'b1; else z = 1'b0; default : z = 1'b0; endcase end // mealy output to delay 1 clk for moore always@(posedge clk or negedge rst_n) begin if (~rst_n) z_o <= 1'b0; else z_o <= z; end endmodule
爲了timing更好,常會在Moore FSM的輸出端加一級DFF
架構以下
module simple_fsm ( clk, rst_n, w_i, z_o ); input clk; input rst_n; input w_i; output z_o; parameter IDLE = 2'b00; parameter S0 = 2'b01; parameter S1 = 2'b10; reg [1:0] curr_state; reg z_o; // state reg + next state logic always@(posedge clk or negedge rst_n) begin if (~rst_n) curr_state <= IDLE; else case (curr_state) IDLE : if (w_i) curr_state <= S0; else curr_state <= IDLE; S0 : if (w_i) curr_state <= S1; else curr_state <= IDLE; S1 : if (w_i) curr_state <= S1; else curr_state <= IDLE; default : curr_state <= IDLE; endcase end // output logic always@(posedge clk or negedge rst_n) begin if (~rst_n) z_o <= 1'b0; else case (curr_state) IDLE : z_o <= 1'b0; S0 : z_o <= 1'b0; S1 : z_o <= 1'b1; default : z_o <= 1'b0; endcase end endmodule
代碼以下:
module simple_fsm ( clk, rst_n, w_i, z_o ); input clk; input rst_n; input w_i; output z_o; parameter IDLE = 2'b00; parameter S0 = 2'b01; parameter S1 = 2'b10; reg [1:0] curr_state; reg [1:0] next_state; reg z_o; // state reg always@(posedge clk or negedge rst_n) begin if (~rst_n) curr_state <= IDLE; else curr_state <= next_state; end // next state logic always@(*) begin case (curr_state) IDLE : if (w_i) next_state = S0; else next_state = IDLE; S0 : if (w_i) next_state = S1; else next_state = IDLE; S1 : if (w_i) next_state = S2; else next_state = IDLE; default : next_state = IDLE; endcase end // output logic always@(posedge clk or negedge rst_n) begin if (~rst_n) z_o <= 1'b0; else case (curr_state) IDLE : z_o <= 1'b0; S0 : z_o <= 1'b0; S1 : z_o <= 1'b1; default : z_o <= 1'b0; endcase end endmodule
注: 本文是在真OO無雙原版上的簡化,如須要了解更詳細信息,請閱讀原文