三段式状态机

状态机是个好东西,写逻辑基本上都是避不开的,按照状态控制和输出是否在一起可以分成一段式、两段式和三段式,我们数电课上都学习过状态机的分析,只是说从来都没有写过,我一开始在学习Verilog和写了一些代码的时候都没有很好的和实际电路联系起来,但是状态机确实是很重要的,一种好的状态机风格可以让代码变得更简单,也不容易出错。

这个部分主要是参考了Clifford E. Cummings的 Synthesizable Finite State Machine Design Techniques Using the New SystemVerilog 3.0 Enhancements

先说说状态机的作用,众所周知FPGA的所有代码是并行运行的,但是很多事情并不是并行的,都是有自己的流程的,因此状态机的引入就是为了更好的叙述整个控制的流程。

状态机的书写风格

一段式

大家一开始会很自然的写成一段式状态机,状态随着输入输出信号不同来变化,Xilinx官方论坛的一个工作人员曾经说过:不同的状态机只是编码风格的问题,如果设计得正确的话效果是一样的,Vivado的综合工具还是很智能的,可以很好的综合逻辑中的状态机,但是作为一名工程师不能止步于这里,一个好的编码风格还是有必要的。当然,上面的帖子有人提出了不同的意见,有人喜欢一段式状态机,觉得很方便和智能,同时还可以避免设计不好带来的latch;也有人觉得一段式状态机不标准,有可能存在不能抵达的状态,同时可读性更差一些。

一段式状态机最大的缺点就是根本不能称之为完整的状态机,因为一个状态可能对应了好几种不同的输入输出,其实应该被拆分成好几个状态才对,而且这样子在分析的时候输出信号实际上是差了一个周期的,因为case判断的是时钟沿来临之前的那个时刻状态的值,这会导致很多的麻烦,写代码的时候也会很痛苦。当然也有好处,一段式状态机书写起来很简单,绝对不会出现latch。

两段式

两段式状态机:两段式状态机的优势在于状态的跳转是在时钟的控制下,每次写的时候只需要考虑在这个状态下的输出是什么,该进入的下一个状态是什么就可以了,标准的两段式状态机的第二段是组合逻辑,这是它的缺点(组合逻辑直接输出的意思是输出的信号可能是有毛刺的,也是不推荐的一种输出的代码风格)。下面十一个两段式状态机的代码,第二段的输出信号最好再用触发器锁一遍,保证下一个模块收到信号的时候不会出现毛刺。

module fsm_cc1_2
    (output reg rd, ds,
        input go, ws, clk, rst_n);
    parameter IDLE = 2'b00,
    READ = 2'b01,
    DLY = 2'b11,
    DONE = 2'b10;
    reg [1:0] state, next;
    always @(posedge clk or negedge rst_n)
        if (!rst_n) state <= IDLE;
    else 
        state <= next;

    always @(state or go or ws) begin
        next = 'bx;
        rd = 1'b0;
        ds = 1'b0;
        case (state)
            IDLE : if (go) next = READ;
            else next = IDLE;
            READ : begin
                rd = 1'b1;
                next = DLY;
            end
            DLY : begin
                rd = 1'b1;
                if (!ws) next = DONE;
                else next = READ;
            end
            DONE : begin
                ds = 1'b1;
                next = IDLE;
            end
        endcase
    end
endmodule

三段式

既然都用D触发器锁存了一遍了,那么不如直接上三段式状态机:第一段状态跳转,第二段用组合逻辑表示状态转移关系,第三段用表示信号的输入输出关系。下面的代码就是一个三段式状态机的例子,第二个always中的的ns = `bx我个人理解是为了让仿真和实测的结果是一致的,要是有人知道其他的原因烦请告诉我

这样的三段式状态机非常的有效,写起来很轻松,我最开始写的就是一段式状态机,经常为了状态的跳转和输出不同而绞尽脑汁,当我用了三段式状态机之后,每个状态只干一件事,写起来就特别的轻松,如果是使用我的vim的话,写个fsm3,然后按F12可以直接调出三段式状态机的模板,如图所示。

module fsm_cc1_3
    (output reg rd, ds,
        input go, ws, clk, rst_n);
    parameter IDLE = 2'b00,
    READ = 2'b01,
    DLY = 2'b11,
    DONE = 2'b10;
    reg [1:0] state, next;
    always @(posedge clk or negedge rst_n)
        if (!rst_n) state <= IDLE;
    else state <= next;
    always @(*) begin
        next = 'bx;
        case (state)
            IDLE : if (go) next = READ;
            else next = IDLE;
            READ : next = DLY;
            DLY : if (!ws) next = DONE;
            else next = READ;
            DONE : next = IDLE;
        endcase
    end
    always @(posedge clk or negedge rst_n)
        if (!rst_n) begin
            rd <= 1'b0;
            ds <= 1'b0;
        end
        else begin
            rd <= 1'b0;
            ds <= 1'b0;
            case (next)
                READ : rd <= 1'b1;
                DLY : rd <= 1'b1;
                DONE : ds <= 1'b1;
            endcase
        end
endmodule

fsm3_snippets

个人的看法

按照数字电路设计的思路来说

One-hot码

One-hot码是一个很有意思的内容,待补充

results matching ""

    No results matching ""