良好的Verilog FSM代碼風格

前言

FSM是電路設計中很是常見的結構,對於這樣常見的結構的正確輸寫很是重要, 良好的代碼風格對於閱讀理解以及後期維護也很是重要。本文總結了目前常見的兩種輸寫FSM的方法html

介紹

FSM目前主要有兩種架構後端

  • Moore FSM
  • Mealy FSM

要讓電路順序地執行計算,最簡單的方法就是生成一個counter, 而後根據counter值去執行相應的操做或計算。但這種方法只能用於很是簡單的控制,且很是不容易維護以及後期功能修改。因此實際上你們都會用標準的FSM來實現複雜控制。架構

Moore FSM架構

clipboard.png

Moore FSM是目前的主流寫法, 它由三塊組成:編碼

  • state register : 由DFF構成,將Next state Logic產生的state存入current register
  • next state logic : 由組合邏輯組成,根據輸入及目前state,產生next state
  • output logic : 組合邏輯, 根據目前state產生輸出

假設輸入爲w_i, 輸出爲z_o, 當輸入連續2個cycle爲高時,則輸出爲1個cycle高spa

clipboard.png

下面是state diagram設計

clipboard.png

三段式編碼

clipboard.png

/**********************************************
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

clipboard.png

兩段式編碼

clipboard.png

代碼以下: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

Mealy FSM

架構以下

clipboard.png

默認它的輸出行爲與Moore有點不同,輸出會早一拍

clipboard.png

原來Moore FSM須要3個state, 改用Mealy FSM只須要2個State

clipboard.png

注意上圖中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
架構以下

clipboard.png

兩段式

clipboard.png

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

三段式

clipboard.png

代碼以下:

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無雙原版上的簡化,如須要了解更詳細信息,請閱讀原文

相關文章
相關標籤/搜索