状态机的组成其实比较简单,要素大致有三个:输入,输出,还有状态。
状态机描述时关键是要描述清楚前面提高的几个状态机的要素,即如何进行状态转移;每个状态的输出是什么;状态转移是否和输入条件相关等。
有人习惯将整个状态机写到一个always模块里面,在该模块中同时描述了状态转移,又描述状态的输入和输出。这种写法一般被称为一段式FSM描述方法;还有一种写法是用2个always模块,其中一个always模块采用同步时序描述状态转移;另一个采用组合逻辑判断状态转移描述状态转移规律,这种写法被称为两段式FSM描述;还有一种是在两段式基础之上发展出来的,这种写法使用3个always模块,一个always模块采用同步时序描述状态转移;第二个采用组合逻辑判断状态转移条件,描述状态转移规律,第三个always模块使用同步时序电路描述每个状态的输出,这种写法成为三段式。
一般推荐后两种方法,也就是两段式和三段式。其原因为:FSM和其他设计一样,最好使用同步时序,以便提高设计的稳定性,消除毛刺。状态转移部分一般是同步时序电路而状态的转移条件的判断是组合逻辑,之所以两段式比一段式更为合理,就在于它将时序逻辑和组合逻辑分别放到不同的always程序快中实现,这样一来便于理解和阅读,二来利于综合器又换代码,更有利于用户添加合适的时序约束条件,利于布局布线器实现设计。
在两段式中,当前状态的输出是用组合逻辑实现的,这样的实现是有产生毛刺的可能性的,而且不利于约束。同样的原因,某些需要引入输出反馈的设计中,两段式会引入组合逻辑的反馈,使综合失败,这是要极力避免的。
三段式与两段式相比,关键在于根据状态转移规律,在上一状态根据输入条件判断当前状态的输出,从而在不出入额外的时钟节拍的前提下,实现了寄存器输出。
一个三段式的状态机大致如下:
module state (nrst,clk,sig1,sig2,out1,out2);
input nrst,clk;
input sig1,sig2;
output out1,out2;
reg out1,out2;
reg [2:0] NS,CS;
parameter [2:0]
IDLE = 3'b000,
S1 = 3'b001,
S2 = 3'b010;
//第一段,状态转换
always @(posedge clk or negedge nrst)
if(!nrst)
CS<= IDLE;
else
CS<= NS;
//第二段,组合逻辑判断
always @(nrst or CS or sig1 or sig2)
begin
NS = 3'bx;//给出默认值
case(CS)
IDLE: begin
if (sig1......) NS = IDLE;
else NS = S1;
end
S1: begin
if(.........) NS = S1;
else NS = xxxx;
S2: .....
endcase
end
//第三段,FSM输出
always @(posedge clk or negedge nrst)
if (!nrst)
{out1,out2}<= 2'b00;
else
begin
{out1,out2}<= 2'b00;
case (NS)
IDLE:......
S1:
endcase
end
endmodule
两段式其实就是将上述的第二段,第三段合一。
三段式写法可概括为如下图:
注意:一三段之中用<=,第二段中用=。
用户377235 2012-4-23 22:20