weiqi7777

FPGA状态机电路综合分析

0
阅读(5032)


           FPGA中,状态机是比较常用的。特别是要处理一些串行执行的操作。但是对于我们编写的状态机,综合出来的电路应该是长什么样子的了?这个在初学的时候都是不关心的,但是深入的话,还是要了解的。

           状态机分为两种,一种是moore型,一种是mealy型。两种的区别就是输出逻辑是否会由输入决定。

           如下图:

           状态机分为三部分模块

第一部分为次态组合逻辑电路,通过将状态输出反馈到次态组合逻辑电路,在和输入信号决定,下一状态是什么状态。

           第二部分就是时序电路,就是一个触发器,将下一状态的值给现在的状态

           第三部分是输出逻辑,通过判断当前的状态,得到输出

clip_image001

 

           在写状态机代码,有三种方式。就是书上说的一段式,二段式,三段式。把3个模块都写在一个always中,就是一段式。将前面两个模块写在一个always中,就是二段式。三个模块分为三个always中写,就是三段式。推荐是使用三段式。这样,逻辑清楚,也便于综合器综合。

 

           考虑以下简单的状态机代码。

      

module led(
    input                   clk,
    input                   rst_n,
    input                   change,
    output  reg [3:0]       led

    );
    localparam   led_0001    = 'd0;
    localparam  led_0010   = 'd1;
    localparam   led_0100    = 'd2;
    localparam   led_1000    = 'd3;
    reg [1:0]   state;
    always@(posedge clk or negedge rst_n) begin

        if(!rst_n)

            state <= led_0001;

        else

            case(state)

            led_0001:

                if(change)

                    state <= led_0010;

            led_0010:

                if(change)

                    state <= led_0100;

            led_0100:

                if(change)

                    state <= led_1000;

            led_1000:

                if(change)

                    state <= led_0001;

        endcase

    end

    
    `define use_case

    `ifdef use_case

    always@* begin

        case(state)

            led_0001:   led = 4'b0001;

            led_0010:   led = 4'b0010;

            led_0100:   led = 4'b0100;

            led_1000:   led = 4'b1000;

        endcase

        end

        `else

        always@* begin

            if(state == led_0001)

                led = 4'b0001;

            else if(state == led_0010)

                led = 4'b0010;

            else if(state == led_0100)

                led = 4'b0100;

            else

                led = 4'b1000;

        end

        `endif

endmodule

功能其实很简单,有4个状态,按照普通二进制编码。每个状态在输入信号change有效的时候状态跳转。在每个状态,4LED输出是不一样的。

在代码中,使用了预编译`ifdef。这里输出逻辑采用ifcase来实现,比较看看综合出来的电路区别。

 

首先是使用case综合。查看综合报告。

clip_image003

综合对代码进行分析,推断出有有一个有限状态机,位数是2,状态是4。还推断出时钟是上升沿,复位是异步低有效。看出,综合器还是比较厉害的。

clip_image005

综合器对状态机的编码进行优化,代码中用的是自然二进制,综合器优化成格雷码。

clip_image007

之后,还得到了用的资源情况。总共使用7LUT2个触发器。一个时钟bufferI/O BUFFER用了6个。

之后是一些时序相关的信息,这里不关心时序。

 

看看综合出来的电路。这个时候要看Technology电路。这个电路才是用LUT和触发器构成的。

clip_image009

这就是综合出来的电路图。用LUT和触发器实现。

电路第一部分就是次态产生组合逻辑电路。第二部分就是时序逻辑,第三部分就是输出组合逻辑电路。

这里,时序逻辑的FFd1是状态的高位,FFd2是状态的低位。

看第一部分的最上面的LU3,这个产生状态机的高位的下一状态。

clip_image011

看看这个逻辑电路的真值表。I2是状态机的高位,I1是状态机的低位,I0是输入change信号。这里分析真值表的前两个。在状态在00的时候,不论输入change信号是什么,状态的高位是不会变化的。因为这一状态和下一状态的高位都是0。下面的真值表可以自己分析下。

这样,就得到状态的高位的次态产生组合逻辑电路。同理,在把状态的其他位的次态产生组合逻辑电路在实现即可了。组合逻辑电路都是使用LUT来实现。因为FPGA的基本结构就是LUT

第二部分就是将次态传递给现态。

第三部分就是输出逻辑了。根据现态,得到输出的值。看第一个LUT2.

clip_image013

I1是状态的高位,I0是状态的低位。当状态为00的时候,输出为1。和代码中写的一样。

这样下来,是不是对状态机的电路综合要明白很多了了。状态机的关键就是第一部分电路,怎么得到下一状态。上面写的代码是比较简单的,所以第一部分电路是比较简单,当写复杂后,这部分电路就复杂了。

在来看看使用if实现区别。

clip_image015

上图是综合出来的电路图,看出和case是一样的。如果去看LUT的真值表的话,发现真值表都是一样的。说明,使用caseif综合出来的电路是一样的。这,怎么可能了?书上说,这两个综合出来的电路应该是不一样的,if是有优先级的。如果是用逻辑门来搭的话,电路是不一样的,但是使用LUT可就不是这样的了,而是两个的电路是一样的了。当然前提是两个电路的功能是一样的。对于同样的输入,输出是一样的。

对于LUT,会预先计算电路的输出,然后填入到LUT中,这样,不管你是用if还是case来写的代码,输出值都是一样,填入到LUT的值也是一样的。但是对于用门电路的话,这就不一样了,if会用较少的资源,而case会用较多的资源。