状态机总结(一段式、两段式、三段式,moore型、mealy型)
来源:集成电路那些事 发布时间:2023-05-24 分享至微信
今天更新一篇状态机的总结,本篇将会为大家总结一下状态机的设计,同时也会提出一些其他文章都没有讲到的点,希望能给大家分享这些经验。
状态机要素
什么是RTL级好的状态机(Finite State Machine,FSM)描述?
  1. FSM要安全,稳定性高(最重要,优先级最高),即FSM不会进入死循环,特别是不会进入非预知的状态,即要求FSM的综合实现结果无毛刺等扰动,要求状态机要完备;
  2. FSM速度快,满足设计的频率要求;
  3. FSM面积小,满足设计的面积要求;
  4. FSM设计要清晰易懂,易维护;
状态机描述方法
一段式描述方法

概述:整个电路用一个进程描述,包含状态转移条件判断、状态输出和状态寄存器转移。


缺点:A、不符合时序和组合逻辑分开描述的代码风格;B、不利于修改、维护;C、不利于附加约束;D、不利于综合器和布局布线器对设计的优化;E、代码冗长。

两段式描述方法

概述:从左往右:第二个进程(纯组合逻辑always模块),描述状态转移条件的判断;第一个进程(同步时序always模块),格式化描述次态到现态的转移;一般情况下是组合逻辑输出,如果时序允许,尽量寄存器输出。


缺点:其输出一般使用组合逻辑描述,而组合逻辑易产生毛刺等不稳定因素。

三段式描述方法
概述:从左往右:第二个进程和第一个进程同两段式状态机的描述方法一样;第三个进程(同步时序always),格式化描述状态的寄存器输出。这里的第三个进程是使用next_state做判断的,所以不会消耗多余的时钟周期。

优点:A、FSM做到了同步寄存器输出;B、消除了组合逻辑输出的不稳定与毛刺的隐患;C、更利于时序路径分组;D、在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。
不同写法的关系
一段式与三段式
一段式建模:必须考虑现态在何种状态转移条件下会进入哪些次态,然后在每个现态的case分支下分别描述每个次态的输出。

三段式建模:只需指定case敏感列表为次态寄存器,然后在每个次态的case分支中描述该状态的输出即可(根本不用考虑状态转移条件)。
两段式与三段式
两段式建模:状态寄存器分割了两部分组合逻辑(状态转移条件组合逻辑)(输出组合逻辑),电路时序路径较短,可以获得更高的性能。

三段式建模:从输入到寄存器的输出路径上,要经过两部分组合逻辑(状态转移条件组合逻辑)(输出组合逻辑),从时序上,这两部分组合逻辑完全可以看为一体,因此这条路径的组合逻辑就比较复杂,该路径的时序相对紧张。

其优点也很突出:可以改善输出的时序条件;还能避免组合电路的毛刺,因此更为推荐这种写法。
三种FSM描述方法比较表
状态机的种类

Moore型状态机:状态机的输出至于当前的状态有关,如下图所示。

Mealy型状态机:状态机的输出不仅与当前的状态有关,还与当前的输入有关,如下图所示。

注意点:以上说明moore型状态机和mealy型状态机的区别所用的是两段式状态机,也就是状态输出都是采用组合逻辑输出。


如果状态输出采用寄存器输出,则需要在输出端加一个寄存器,这样会多消耗一个时钟周期,但是功能不会发生错误。


三段式状态机中为了不消耗一个额外的时钟周期,采用next_state作为判断条件,但是如果采用mealy型状态机,则此时的输入将会和next_state一起作为判断条件来判断输出,这样就会发生功能错误,如下图所示。

正确的做法是将输出_temp与当前输入再用组合逻辑输出,如下图所示,这样功能不会发生错误。


但是其实这种做法是多此一举的,因为这样做输出还是组合逻辑,没有采用寄存器输出,并且这条通路的时序相对紧张。


博主这样的画法只是想说明保证三段式mealy状态机功能正确的做法。

状态机举例

本节中,博主选择了两道HDLbits中的题目,来为大家更好的描述三种状态机写法以及moore、mealy状态机之间的差异。

三种描述风格

状态转移图如上图所示,下面是一段式、两段式、三段式的描述风格。
一段式描述风格:
module top_module( input clk, input areset, // Asynchronous reset to state B input in, output reg out);//
parameter A=1'b0, B=1'b1; reg state;
always@(posedge clk or posedge areset)begin if(areset)begin state <= B; out <= 1'b1; end else begin case(state) B:begin if(in == 1'b1)begin state <= B; out <= 1'b1; end else begin state <= A; out <= 1'b0; end end A:begin if(in == 1'b1)begin state <= A; out <= 1'b0; end else begin state <= B; out <= 1'b1; end end default:begin state <= B; out <= 1'b1; end endcase end end
endmodule
两段式描述风格:

输出写在下一状态转移组合逻辑中。

module top_module( input clk, input areset, // Asynchronous reset to state B input in, output reg out);//
parameter A=1'b0, B=1'b1; reg current_state, next_state;
always@(posedge clk or posedge areset)begin if(areset)begin current_state <= B; end else begin current_state <= next_state; end end
always@(*)begin case(current_state) B:begin if(in == 1'b1)begin next_state = B; end else begin next_state = A; end out = 1'b1; end A:begin out = 1'b0; if(in == 1'b1)begin next_state = A; end else begin next_state = B; end out = 1'b0; end endcase end
endmodule
输出与下一状态转移组合逻辑分开。
module top_module( input clk, input areset, // Asynchronous reset to state B input in, output reg out);//
parameter A=1'b0, B=1'b1; reg current_state, next_state;
always@(posedge clk or posedge areset)begin if(areset)begin current_state <= B; end else begin current_state <= next_state; end end
always@(*)begin case(current_state) B:begin if(in == 1'b1)begin next_state = B; end else begin next_state = A; end end A:begin if(in == 1'b1)begin next_state = A; end else begin next_state = B; end end endcase end
always@(*)begin if(current_state == B)begin out = 1'b1; end else begin out = 1'b0; end end
/* //second way //assign out = (current_state == B); */
/* //third way always@(*)begin case(current_state) B:begin out = 1'b1; end A:begin out = 1'b0; end endcase end */
endmodule
三段式描述风格
module top_module( input clk, input areset, // Asynchronous reset to state B input in, output reg out);//
parameter A=1'b0, B=1'b1; reg current_state, next_state;
always@(posedge clk or posedge areset)begin if(areset)begin current_state <= B; end else begin current_state <= next_state; end end
always@(*)begin case(current_state) B:begin if(in == 1'b1)begin next_state = B; end else begin next_state = A; end end A:begin if(in == 1'b1)begin next_state = A; end else begin next_state = B; end end endcase end
always@(posedge clk or posedge areset)begin if(areset)begin out <= 1'b1; end else if(next_state == B)begin out <= 1'b1; end else begin out <= 1'b0; end end
endmodule

说明

一段式状态机描述中没有区分current_state和next_state,将所有的状态转移和输出逻辑写在一个always时序模块中,代码相对冗长,不利于分析电路结构。

两段式状态机描述中采用组合逻辑描述输出,其中两种大的写法,第一种是将输出逻辑融合到下一状态转移组合逻辑中,第二种是将输出和下一状态转移组合逻辑分开。

大家要注意,这两种写法映射到电路中没有任何区别。有一点困扰的地方是大家通常将第二种写法叫做三段式状态机的第三段。

从广义上来讲,这种叫法没有错,因为毕竟这三段分割明显,每一段做什么事情都很好理解,但是更细化,从电路结构来讲,这种写法只能称为两段式状态机,next_state到current_state采用时序逻辑,状态转移和输出采用组合逻辑,这是两段式状态机的标志。

三段式状态机描述中采用时序逻辑描述输出,为了节省一拍,采用next_state作为判断条件。

特别注意,这里只有A和B两个状态,只需要1bit,所以博主两段式和三段式的case中省略了default,这里建议不论条件是否列全,都应该加上default,博主没有加default的做法不值得提倡。
两种状态机
检测“101”序列,题目要求重叠检测(比如对于序列“101010”,重叠检测会输出两次高电平,不重叠检测会输出一次高电平)。

moore型状态机:状态转移图如下:

module top_module (    input clk,    input aresetn,    // Asynchronous active-low reset    input x,    output reg z ); 
parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2, S3 = 2'd3; reg [1:0] current_state; reg [1:0] next_state;
always@(posedge clk or negedge aresetn)begin if(aresetn == 1'b0)begin current_state <= S0; end else begin current_state <= next_state; end end
always@(*)begin case(current_state) S0:begin next_state = x ? S1 : S0; end S1:begin next_state = x ? S1 : S2; end S2:begin next_state = x ? S3 : S0; end S3:begin next_state = x ? S1 : S2; end default:begin next_state = S0; end endcase end
always@(posedge clk or negedge aresetn)begin if(aresetn == 1'b0)begin z <= 1'b0; end else begin if(next_state == S3)begin z <= 1'b1; end else begin z <= 1'b0; end end end
endmodule
mealy型状态机:状态转移图如下:
module top_module (    input clk,    input aresetn,    // Asynchronous active-low reset    input x,    output z ); 
parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2; reg [1:0]current_state; reg [1:0]next_state;
always@(posedge clk or negedge aresetn)begin if(aresetn == 1'b0)begin current_state <= S0; end else begin current_state <= next_state; end end
always@(*)begin case(current_state) S0:begin next_state = x ? S1 : S0; end S1:begin next_state = x ? S1 : S2; end S2:begin next_state = x ? S1 : S0; end default:begin next_state = S0; end endcase end
assign z = ((current_state == S2) && (x == 1'b1)) ? 1'b1 : 1'b0;
/* //second way always@(*)begin case(current_state) S0:begin z = 1'b0; end S1:begin z = 1'b0; end S2:begin z = x; end endcase end */
endmodule

上面两组代码就是mealy型状态机分别使用“两段式状态机”和“三段式状态机”完成的写法,这里加了引号,因为不是标准的两段式和三段式,我们最常用的两段式和三段式主要都是针对moore型状态机所说。

说明
我们从上面的状态转移图可以看出,moore型状态机要比mealy型状态机多一个状态,也就意味着mealy型状态机要比moore型状态机快一个周期,因为mealy型状态机使用当前输入和当前状态共同判断,moore型状态机不需要当前输入。
总结

今天的这篇博客,基于博主自己对状态机的理解所写,包括博主曾经踩过的一些坑。


博客中对三种状态机写法,两类状态机都有一些直观的描述,其中三种状态机的写法那部分参考了邸志雄老师在慕课的课程《芯动力——硬件加速设计方法》,感兴趣的同学可以去慕课观看,希望能给大家带来帮助。


版权声明:本文为CSDN博主「wangkai_2019」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/wangkai_2019/article/details/107692192

以上内转载自:CSDN博主「wangkai_2019」,版权归原作者,如需转载本文,请联系原作者,文章中其它相关链接也请去原文链接内获取,欢迎大家留言讨论,谢谢!



简介


集成电路那些事(ID:ICKnowledge)专注于集成电路相关内容,是一个IC讯息的汇聚地,分享、转载好文一起学习,一起进步。

扫码关注

动动你的发财手,给个“在看”呗!

[ 新闻来源:集成电路那些事,更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj]
存入云盘 收藏
举报
全部评论

暂无评论哦,快来评论一下吧!