1. 状态机的基本概念
数字系统分两大类FSM:Moore和Mealy。FSM是用来表示有限个状态之间转移和动作等行为。
1.2 Moore状态机
Moore FSm由Edward F. Moore 提出。特点是输出只由当前状态确定,与输入没有关系。
Moore FSM状态图中每一个状态都包含一个输出信号。一旦当前状态改变几乎会立即导致输出改变。Moore FSM输出在时钟脉冲的有效边沿后的有限个门延迟之后才会达到稳定值,Moore最大的特点是将输入和输出信号隔离开来。
图1 Moore 状态机示意图
1.3 Mealy状态机
Mealy FSM是由G.H.Mealy在1951年提出来的,输出和当前状态也和输入有关系,因此在状态转移图中每条转移边需要包含输入和输出的信息,每一个Mealy机都有一个等价的Moore机。
Mealy FMS的输出直接受输入的直接影响,而输入的信号可能在一个时钟周期内任何时刻发生改变,所以Mealy FSM对输入的响应要比Moore FSM早一个周期,而且输入信号的噪声也可能影响到输出信号。
图2 Mealy 状态机示意图
1.3状态初始化
初始化是对FSM内部的所有reg还有mem进行复位和初始化,一定要防止出现伪初始化或者不完全初始化的情况,特别针对一些总线或者有位宽要求的信号和变量。
未完全初始化的示例:
always @(posedge clk or negedge rst_n) begin if(!rst_n) state <= IDLE; else case(state) IDLE:begin S[0] <=1'b1; state <=ACT1; end ACT1:begin S[1] <=1'b1; state <=ACT2; end ACT2:begin S[2] <=1'b1; state <=CMP; end CMP:begin S[3] <=1'b1; state <=IDLE; end default:state <= IDLE; endcase end
这个FSM表示在不同的状态给S[3:0]的不同位置,在异步复位的地方只是对state初始化,但是对于S[3:0]并没有初始化,解决这个初始化的最好方法就是对所有的输出都进行初始化。从根本上讲,所有的初始化动作都需要对FSM中的每个输出信号和变量进行初始化,另外要特别注意default分支语句,避免进入死锁。修改如下例:
always @(posedge clk or negedge rst_n) begin if(!rst_n) begin state <= IDLE; S <= 4'b0000; end else case(state) IDLE:begin S[0] <=1'b1; state <=ACT1; end ACT1:begin S[1] <=1'b1; state <=ACT2; end ACT2:begin S[2] <=1'b1; state <=CMP; end CMP:begin S[3] <=1'b1; state <=IDLE; end default:state <= IDLE; endcase end
1.4 Full Case和Parallel Case
Full Case在Sunplify中一般采用/*synthesis full_case*/来实现,Parallel case在Sunplify中一般采用/*synthesis parallel_case*/来实现
1.4.1 Full Case下FSM设计
module syntax_ctrl(s0,s1,s2,s3,next) //数据声明 input s0,s1,s2,s3; output reg[1:0] next; // parameter IDLE = 4'b1xxx, READ = 4'bx1xx, TALK = 4'bxx1x, STOP = 4'bxxx1; // always @(s0 or s1 or s2 or s3) begin casex({s0,s1,s2,s3}) IDLE: next <=0; READ: next <=1; TALK: next <=2; STOP: next <=3; default: next <=0; endcase end endmodule
1.4.2 Parallel case FSM实现
module syntax_ctrl(s0,s1,s2,s3,next) //数据声明 input s0,s1,s2,s3; output reg[1:0] next; // parameter IDLE = 4'b1xxx, READ = 4'bx1xx, TALK = 4'bxx1x, STOP = 4'bxxx1; // always @(s0 or s1 or s2 or s3) begin casex({s0,s1,s2,s3}) IDLE: next <=0; READ: next <=1; TALK: next <=2; STOP: next <=3; default: next <=0; endcase end endmodule
两者区别在:
Full case中FSM把所有的编码向量与case中某个分支匹配,如果编码是4bits则有16个状态编码向量同case中的某个分支映射起来。
Parallel case 中,每个case中判断条件表达式有且仅有一个分支语句与之对应。
Full case可以增加设计的安全性,Parallel case可以优化状态机的逻辑编码,不过,一般比较推荐采用Parallel case,因为从功能和门级仿真的结果来看,Parallel case比较符合硬件行为的要求。
注意:在一般的仿真工具并不认识上面所述的注释,所以一般而言当需要使用优先级编码逻辑的时候,采用casez语句,可以确保case语句涉及的是全面的;当要使用Parallel case时采用case语句,而且case语句中各条分支语句必须是相互排斥的。