4

前言

FSM是电路设计中非常常见的结构,对于这样常见的结构的正确输写非常重要, 良好的代码风格对于阅读理解以及后期维护也非常重要。本文总结了目前常见的两种输写FSM的方法

介绍

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高

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

下面是相应的TB

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

仿真波形如下:

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@(*)
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

其他

还有其他二段式,或者一段式,但都不推荐使用。
从条理上讲三段式是最清晰的, 易于理解,便于维护

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无双原版上的简化,如需要了解更详细信息,请阅读原文


harriszh
338 声望131 粉丝

做些有趣的事,留些有用的存在


引用和评论

0 条评论