Verilog | 有限状态机Case

今天尝试将几个有限状态机,转换为Verilog代码,有限状态机(Finite-State Machine,FSM),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。状态机不仅是一种电路的描述工具,而且也是一种思想方法,在电路设计的系统级和 RTL 级有着广泛的应用。

以下介绍转载自菜鸟runoob.com

状态机类型

Verilog 中状态机主要用于同步时序逻辑的设计,能够在有限个状态之间按一定要求和规律切换时序电路的状态。状态的切换方向不但取决于各个输入值,还取决于当前所在状态。状态机可分为 2 类:Moore 状态机和 Mealy 状态机。

Moore 型状态机

Moore 型状态机的输出只与当前状态有关,与当前输入无关。

输出会在一个完整的时钟周期内保持稳定,即使此时输入信号有变化,输出也不会变化。输入对输出的影响要到下一个时钟周期才能反映出来。这也是 Moore 型状态机的一个重要特点:输入与输出是隔离开来的。

Verilog | 有限状态机Case_第1张图片

Mealy 型状态机

Mealy 型状态机的输出,不仅与当前状态有关,还取决于当前的输入信号。

Mealy 型状态机的输出是在输入信号变化以后立刻发生变化,且输入变化可能出现在任何状态的时钟周期内。因此,同种逻辑下,Mealy 型状态机输出对输入的响应会比 Moore 型状态机早一个时钟周期。

Verilog | 有限状态机Case_第2张图片

状态机设计流程

根据设计需求画出状态转移图,确定使用状态机类型,并标注出各种输入输出信号,更有助于编程。一般使用最多的是 Mealy 型 3 段式状态机。

以下例题来源 HDLbits。

Case1:异步Reset状态机

Verilog | 有限状态机Case_第3张图片

接收到areset会将状态重置回B,如果状态在B,则out输出1,状态在A则out输出0。输出只跟状态有关,它是一个Moore型状态机。

module top_module (
  input clk,
  input in,
  input areset,
  output out
);


  // Give state names and assignments. I'm lazy, so I like to use decimal numbers.
  // It doesn't really matter what assignment is used, as long as they're unique.
  parameter A=0, B=1;
  reg state;    // Ensure state and next are big enough to hold the state encoding.
  reg next;
    
    
    // A finite state machine is usually coded in three parts:
    //   State transition logic 状态转换逻辑
    //   State flip-flops 状态触发器
    //   Output logic 输出逻辑
    // It is sometimes possible to combine one or more of these blobs of code
    // together, but be careful: Some blobs are combinational circuits, while some
    // are clocked (DFFs).
    
    
    // Combinational always block for state transition logic. Given the current state and inputs,
    // what should be next state be?
    // Combinational always block: Use blocking assignments.
    // 使用组合逻辑,决定下一个状态
    always@(*) begin
    case (state)
      A: next = in ? A : B;
      B: next = in ? B : A;
    endcase
    end
    
    
    
    // Edge-triggered always block (DFFs) for state flip-flops. Asynchronous reset.
    // 使用时序逻辑,在时钟上升沿和areset上升沿进行状态转换
    always @(posedge clk, posedge areset) begin
    if (areset) state <= B;    // Reset to state B
        else state <= next;      // Otherwise, cause the state to transition
  end
    
    
    
  // Combinational output logic. In this problem, an assign statement is the simplest.
  // In more complex circuits, a combinational always block may be more suitable.
  // 定义输出逻辑,他与状态强关联
  assign out = (state==B);


  
endmodule

Verilog | 有限状态机Case_第4张图片

Case2:同步Reset自动机

采用同步的方法,实现Case1中的自动机。

// Note the Verilog-1995 module declaration syntax here:
module top_module(clk, reset, in, out);
    input clk;
    input reset;    // Synchronous reset to state B
    input in;
    output out;//  


    // Fill in state name declarations
  parameter A = 0, B = 1;
    reg present_state, next_state;


    always @(posedge clk) begin
        if (reset) begin  
            present_state = B;
            out = 1;
        end else begin
            case (present_state)
                // State transition logic
                A : next_state = in ? A : B;
                B : next_state = in ? B : A;
            endcase


            // State flip-flops
            present_state = next_state;   


            case (present_state)
                A : out = 0;
                B : out = 1;
            endcase
        end
    end


endmodule

Verilog | 有限状态机Case_第5张图片

Case2采用了同步复位,使得复位信号在时钟上升沿有效,所以在85ns时,reset仍为0,不会立即置state为B,时序上会较Case1延迟一个周期。Case2在同步系统中更常见,适合需要在时钟边沿更新的情况,Case1适合需要更快响应的场合。

Case3:状态转换表表示的状态机

Verilog | 有限状态机Case_第6张图片

实现基于以上状态转换表进行状态转换的组合逻辑,采用 A=4'b0001, B=4'b0010, C=4'b0100, D=4'b1000的状态编码(每个状态仅一位是有效的),这样的OneHot设计将简化状态机的跳转设计。

module transition_module(
    input in,
    input [3:0] state,
    output [3:0] next_state,
    output out); //


    parameter A=0, B=1, C=2, D=3;


    // State transition logic: Derive an equation for each state flip-flop.
    // onehot 保证了state中只有一个是有效的
    assign next_state[A] = (~in & state[A]) | (~in & state[C]);
    assign next_state[B] = (in & state[A]) | (in & state[B]) | (in & state[D]);
    assign next_state[C] = (~in & state[B]) | (~in & state[D]);
    assign next_state[D] = (in & state[C]);


    // Output logic: 
    assign out = state[D];


endmodule

使用上面的状态转换逻辑,设计异步Reset的状态机:

module top_module(
    input clk,
    input in,
    input areset,
    output out); //


    // State transition logic, one hot
    parameter A=4'b0001, B=4'b0010, C=4'b0100, D=4'b1000;
    reg [3:0] state, next_state;
    // 例化一个状态转换逻辑
    transition_module instance1(
        .in(in),
        .state(state),
        .next_state(next_state),
        .out(out));


    // State flip-flops with asynchronous reset
    always @(posedge clk or posedge areset) begin
        if(areset) state <= A;
        else state <= next_state;
    end


endmodule

Case4:串行接收器

最后一个例子我们将实现一个串行接收器,在许多较旧的串行通信协议中,每个数据字节与起始位和停止位一起发送,以帮助接收方从位流中划分字节。一种常见的方案是使用一个起始位(0),8个数据位和1个停止位(1)。当没有任何传输(空闲)时,线路也处于逻辑1。

设计一个有限状态机,当给定一个比特流时,它将识别字节是否被正确接收。它需要识别起始位,等待所有8个数据位以及一个校验位,然后验证停止位是否正确。如果停止位没有在预期的时间出现,FSM必须等待,直到找到一个停止位,然后再尝试接收下一个字节。

完成一个字节接收后且校验位正确时模块应当输出done=1以及此时的out_byte为字节内容,一个样例如下图所示。

校验块不对或者没有收到END,都不应该使能done:

Verilog | 有限状态机Case_第7张图片

设计状态机(勘误:WAIT状态会跳转到IDLE):

Verilog | 有限状态机Case_第8张图片

校验值处理:使用异或规约操作,对9个位归约,值为1说明当前1的个数为奇数。

Verilog编码:

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); 
    parameter IDLE = 0, START = 1, R1 = 2, R2 = 3, R3 = 4, R4 = 5, R5 = 6, R6 = 7, R7 = 8, R8 = 9, END = 10, OUT = 11, WAIT = 12;
    reg [3:0] state, next_state;
    reg [8:0] result;
    
    always @(*) begin
        case(state)
            IDLE: next_state = in ? IDLE : START;
            START: next_state = R1;
            R1: next_state = R2;
            R2: next_state = R3;
            R3: next_state = R4;
            R4: next_state = R5;
            R5: next_state = R6;
            R6: next_state = R7;
            R7: next_state = R8;
            R8: next_state = END;
            END: next_state = in ? OUT : WAIT;
            OUT: next_state = in ? IDLE: START;
            WAIT: next_state = in ? IDLE: WAIT;
        endcase
    end
    
    always @(posedge clk) begin
        if(reset) state <= IDLE;
        else state <= next_state;
        
        // USE last cycle state 
        case (state)
            START: result[0] <= in;
            R1: result[1] <= in;
            R2: result[2] <= in;
            R3: result[3] <= in;
            R4: result[4] <= in;
            R5: result[5] <= in;
            R6: result[6] <= in;
            R7: result[7] <= in;
            R8: result[8] <= in;
        endcase
    end
    
    assign done = (state == OUT) && (^result[8:0]);
    assign out_byte = result[7:0];


endmodule

感谢你阅读到这里。

你可能感兴趣的:(fpga开发)