状态机学习资料

6.2.3 .2 两段式状态机描述方法(推荐写法)

为了使FSM 描述清晰简介,易于维护,易于附加时序约束,使综合器和布局布线器更好的优化设计,推荐使用两段式FSM 描述方法。

本例的两段式描述代码如下:

//2-paragraph method to describe FSM

//Describe sequential state transition in 1 sequential always block

//State transition conditions in the other combinational always block

//Package state output by task. Then register the output

module state2 ( nrst,clk,

i1,i2,

o1,o2,

err

);

input nrst,clk;

input i1,i2;

output o1,o2,err;

reg o1,o2,err;

reg [2:0] NS,CS;

parameter [2:0] //one hot with zero idle

    IDLE = 3'b000,

    S1 = 3’ b001,

    S2 = 3’ b010,

    ERROR = 3’ b100;

//sequential state transition

always @ (posedge clk or negedge nrst)

    if (!nrst)

        CS <= IDLE;

    else

        CS <=NS;

//combinational condition judgment

always @ (CS or i1 or i2)

begin

NS = 3'bx;

ERROR_out;

case (CS)

    IDLE: begin

        IDLE_out;

        if (~i1) NS = IDLE;

        if (i1 && i2) NS = S1;

        if (i1 && ~i2) NS = ERROR;

        end

    S1: begin

        S1_out;

        if (~i2) NS = S1;

        if (i2 && i1) NS = S2;

        if (i2 && (~i1)) NS = ERROR;

        end

    S2: begin

        S2_out;

        if (i2) NS = S2;

        if (~i2 && i1) NS = IDLE;

        if (~i2 && (~i1)) NS = ERROR;

        end

    ERROR: begin

        ERROR_out;

        if (i1) NS = ERROR;

        if (~i1) NS = IDLE;

        end

    endcase

end

//output task

task IDLE_out;

{o1,o2,err} = 3'b000;

endtask

task S1_out;

{o1,o2,err} = 3'b100;

endtask

task S2_out;

{o1,o2,err} = 3'b010;

endtask

task ERROR_out;

{o1,o2,err} = 3'b111;

endtask

endmodule

两段式写法是推荐的FSM 描述方法之一,在此我们仔细讨论一下代码结构。两段式FSM 的核心就是:一个always 模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律。两段式写法可以概括为图6-5 描述的结构。

6-5 两段式FSM 描述结构图

本例中,同步时序描述状态转移的always 模块代码如下:

always @ (posedge clk or negedge nrst)

if (!nrst)

    CS <= IDLE;

else

    CS <=NS;

其实这是一种程式化的描述结构,无论具体到何种FSM 设计,都可以定义两个状态寄存器“CS”和“NS”,分别代表当前状态和下一状态,然后根据所需的复位方式(同步复位或异步复位),在时钟沿到达时将NS 赋给CS。需要注意的是这个同步时序模块的赋值要采用非阻塞赋值“<=”。

本例中,另一个采用组合逻辑判断状态转移条件的always 模块代码如下:

//combinational condition judgment

always @ (nrst or CS or i1 or i2)

begin

    NS = 3'bx;

    ERROR_out;

    case (CS)

        IDLE: begin

            IDLE_out;

            if (~i1) NS = IDLE;

            if (i1 && i2) NS = S1;

            if (i1 && ~i2) NS = ERROR;

            end

        S1: begin

            S1_out;

            if (~i2) NS = S1;

            if (i2 && i1) NS = S2;

            if (i2 && (~i1)) NS = ERROR;

            end

        S2: begin

            S2_out;

            if (i2) NS = S2;

            if (~i2 && i1) NS = IDLE;

            if (~i2 && (~i1)) NS = ERROR;

            end

        ERROR: begin

            ERROR_out;

            if (i1) NS = ERROR;

            if (~i1) NS = IDLE;

            end

    endcase

end

这个使用组合逻辑判断状态转移条件的always 模块也可以看成格式化的书写结构。其中always 的敏感列表为当前状态“CS”,复位信号和输入条件(如果是米勒状态机,则必须有输入条件;如果是摩尔状态机,一般敏感表和后续逻辑判定没有输入),请大家注意电平敏感表必须列完整。本例中这段电平敏感列表为:

always @ (nrst or CS or i1 or i2)

一般来说,在这个组合always 敏感表下先写一个默认的下一状态“NS”的描述,然后根据实际的状态转移条件由内部的case 或者if...else 条件判断确定正确的转移。如本例中下面这段代码,

……

begin

    NS = ERROR;

    ERROR_out;

case (CS)

……

推荐在敏感表下的默认状态为不定状态X,这样描述的好处有两个:第一在仿真时可以很好的考察所设计的FSM 的完备性,如果所设计的FSM 不完备,则会进入任意状态,仿真很容易发现;第二个好处是综合器对不定态X 的处理是“Don’t Care”,即任何没有定义的状态寄存器向量都会被忽略。这里赋值不定态的效果和使用casez casex 替代case 的效果非常相似。在每个case 模块的内部的结构也非常相似,都是先描述当前状态的组合逻辑输出,然后根据输入条件(米勒FSM)判定下一个状态。该组合逻辑模块中所有的赋值推荐采用阻塞赋值“=”。

请大家注意,虽然下一状态寄存器NS 为寄存器类型,但是在两段式FSM 的判断状态转移

条件的always 模块中,实际上对应的真实硬件电路是纯组合逻辑电路。

对于每个输出,一般用组合逻辑描述,比较简便的方法是用task/endtask 将输出封装起来,这样做的好处不仅仅是写法简单,而且利于复用共同的输出。例如本例中S1 状态的输出被封装为S1_out,在组合逻辑always 模块中直接调用即可。

task S1_out;

{o1,o2,err} = 3'b100;

endtask

组合逻辑容易产生毛刺,因此如果时序允许,请尽量对组合逻辑的输出插入一个寄存器节拍,这样可以很好的保证输出信号的稳定性。

6.2.3 .3 三段式状态机描述方法(推荐写法)

两段式FSM 描述方法虽然有很多好处,但是它有一个明显的弱点就是其输出一般使用组合逻辑描述,而组合逻辑易产生毛刺等不稳定因素,并且在FPGA/CPLD 等逻辑器件中过多的组合逻辑会影响实现的速率(这点与ASIC 设计不同)。所以在上节我们特别提到了在两段式FSM 描述方法中,如果时序允许插入一个额外的时钟节拍,则尽量在在后级电路对FSM 的组合逻辑输出用寄存器寄存一个节拍,则可以有效地消除毛刺。但是很多情况下,设计并不允许额外的节拍插入(Latency),此时,解决之道就是采用3 段式FSM 描述方法。三段式描述方法与两段式描述方法相比,关键在于使用同步时序逻辑寄存FSM 的输出。

本例的三段式描述代码如下:

//3-paragraph method to describe FSM

//Describe sequential state transition in the 1st sequential always block

//State transition conditions in the 2nd combinational always block

//Describe the FSM out in the 3rd sequential always block

module state2 ( nrst,clk,

i1,i2,

o1,o2,

err

);

input nrst,clk;

input i1,i2;

output o1,o2,err;

reg o1,o2,err;

reg [2:0] NS,CS;

parameter [2:0] //one hot with zero idle

    IDLE = 3'b000,

    S1 = 3'b001,

    S2 = 3'b010,

    ERROR = 3'b100;

//1st always block, sequential state transition

always @ (posedge clk or negedge nrst)

if (!nrst)

    CS <= IDLE;

else

    CS <=NS;

//2nd always block, combinational condition judgment

always @ (nrst or CS or i1 or i2)

begin

    NS = 3'bx;

    case (CS)

        IDLE: begin

            if (~i1) NS = IDLE;

            if (i1 && i2) NS = S1;

            if (i1 && ~i2) NS = ERROR;

            end

        S1: begin

            if (~i2) NS = S1;

            if (i2 && i1) NS = S2;

            if (i2 && (~i1)) NS = ERROR;

            end

        S2: begin

            if (i2) NS = S2;

            if (~i2 && i1) NS = IDLE;

            if (~i2 && (~i1)) NS = ERROR;

            end

        ERROR: begin

            if (i1) NS = ERROR;

            if (~i1) NS = IDLE;

            end

    endcase

end

//3rd always block, the sequential FSM output

always @ (posedge clk or negedge nrst)

if (!nrst)

{o1,o2,err} <= 3'b000;

else

begin

    {o1,o2,err} <= 3'b000;

    case (NS)

        IDLE: {o1,o2,err}<=3'b000;

        S1: {o1,o2,err}<=3'b100;

        S2: {o1,o2,err}<=3'b010;

        ERROR: {o1,o2,err}<=3'b111;

    endcase

end

endmodule

三段式写法可以概括为图6-6 描述的结构。

6-6 三段式FSM 描述结构图

对比一下上节两段式FSM 的描述,读者可以清晰发现三段式与两段式FSM 描述的最大区别在于两段式采用了组合逻辑输出,而三段式巧妙地根据下一状态的判断,用同步时序逻辑寄存FSM 的输出。本例中就是下面一段代码,

always @ (posedge clk or negedge nrst)

if (!nrst)

    {o1,o2,err} <= 3'b000;

else

    begin

        {o1,o2,err} <= 3'b000;

        case (NS)

            IDLE: {o1,o2,err}<=3'b000;

            S1: {o1,o2,err}<=3'b100;

            S2: {o1,o2,err}<=3'b010;

            ERROR: {o1,o2,err}<=3'b111;

        endcase

end

有的读者可能会问,一段式写法也是用寄存器同步了FSM 的输出,为什么前面介绍一段式的输出代码容易混淆,不利于维护呢?请大家对比一下 6.2.3 .1 小节的这段一段式输出的代码,

……

case (NS)

IDLE: begin

    if (~i1) begin{o1,o2,err}<=3'b000;NS <= IDLE; end

    if (i1 && i2) begin{o1,o2,err}<=3'b100;NS <= S1; end

    if (i1 && ~i2) begin{o1,o2,err}<=3'b111;NS <= ERROR;end

end

……

通过对比,可以清晰地看到:使用一段式建模FSM 的寄存器输出的时候,必须要综合考虑现态在何种状态转移条件下会进入哪些次态,然后在每个现态的case 分支下分别描述每个次态的输出,这显然不符合思维习惯;而三段式建模描述FSM 的状态机输出时,只需指定case 敏感表为次态寄存器,然后直接在每个次态的case 分支中描述该状态的输出即可,根本不用考虑状态转移条件。本例的FSM 很简单,如果设计的FSM 相对复杂,三段式的描述优势就会凸显出来。

另一方面,三段式描述方法与两段式描述相比,虽然代码结构复杂了一些,但是换来的优势是使FSM 做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD 等可编程逻辑器件上的综合与布局布线效果更佳。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值