【FPGA基础】状态机

发布时间 2023-12-21 16:30:36作者: AnchorX

状态机由状态寄存器和组合逻辑电路组成;在不同的当前状态下,能够控制信号的变化进行状态的转移,从而实现相关信号的赋值,完成特定控制时序的设计。

状态机的三个基本要素:

       状态变迁(当前状态current_state和下一状态next_state

       输入条件(状态变化的触发事件

       输出赋值(状态机设计的主要目的

 

有限状态机(FSM)的分类

       若输出只和状态有关而和输入无关(无条件状态转移),则称为Moore状态机;

       输出不仅和状态有关而且和输入有关(有条件状态转移),则称为Mealy状态机;

(Moore型只在某些上电初始化中可能会用到,实际上以Mealy型为主。不过也无需太注意使用哪一种状态机实现方式。)

 

关于状态的变迁

       外部输入信号产生的“特定事件”通常是引起状态变迁的先决条件,但不是必要条件;(有些时候状态变迁是自然发生的,不需要外部输入)

       状态机可以在一些有限状态间进行“无限循环”;也可以进行“有限”循环或单次运行,最终进入只有一个复位才能退出的“终结状态”。

 

状态机设计方法(三段式或者又称两段式)

  第一段状态机:时序逻辑,状态锁存

  第二段状态机:组合逻辑,判断当前状态和输入信号变化,输出下一状态

  当前状态下,时序逻辑对输出信号赋值

 

例子:

用fifo的计数器控制,写半满时开始读,读半空时开始写,其它时间既读又写。

// 利用状态机对fifo进行半空半满的读写
module fifo_example;

// 三段式状态机
always @(posedge clk100m) begin
    if(Rst == 1'b1)
        curr_state <= #TCQ_STA_IDLE;
    else
        curr_state <= #TCQ_next_state;
end

// Calculate the next state
always @ ( * ) begin
    case(curr_state)
        STA_IDLE:begin
            if (full == 1'b0) // fifo IP核的性质,初始化状态full为1
                next_state <= STA_WRITING;
            else
                next_state <= STA_IDLE;
        end

        STA_WRITING:begin
            if (wr_data_count > 8'd200) // 已写入200个数
                next_state <= STA_READING;
            else
                next_state <= STA_WRITING;
        end
        
        STA_READING:begin
            if (rd_data_count < 6'd20)  // 可读取的数小于20
                next_state <= STA_WRITING;
            else
                next_state <= STA_READING;
        end

        default :begin
            next_state <= STA_IDLE;
        end
    endcase
end

// state output
always @(posedge clk100m) begin
    if (Rst == 1'b1) begin
        wr_en        <= #TCQ 1'b0;
        rd_en        <= #TCQ 1'b0;
        din          <= #TCQ 8'd0;
        din_r        <= #TCQ 8'd0;
    end
    else case (curr_state)
        STA_IDLE: begin
            wr_en        <= #TCQ 1'b0;
            rd_en        <= #TCQ 1'b0;
            din          <= #TCQ 8'd0;
            din_r        <= #TCQ 8'd0;
        end

        STA_WRITING:begin
            wr_en        <= #TCQ 1'b1;
            rd_en        <= #TCQ 1'b0;
            if (din == 8'd255)
                din      <= #TCQ 8'd0;
            else 
                din      <= #TCQ din + 8'd1;
            din_r        <= #TCQ din;
        end

        STA_READING:begin
            wr_en        <= #TCQ 1'b0;
            rd_en        <= #TCQ 1'b1;
        end
    endcase
end

endmodule //fifo_example