Verilog -- 状态机
参考:
https://blog.csdn.net/woshiyuzhoushizhe/article/details/95866063
https://blog.csdn.net/qq_34070723/article/details/100737225
https://www.cnblogs.com/flyuea/p/8421939.html
MOORE 与 MEALEY 状态机的特征?
Moore 状态机的输出仅与当前状态值有关, 且只在时钟边沿到来时才会有状态变化。次态=f(现状,输入),输出=f(现状)
Mealy 状态机的输出不仅与当前状态值有关, 而且与当前输入值有关。次态=f(现状,输入),输出=f(现状,输入)
描述同一个事务,mealy的状态更少。
一段式状态机
一段式状态机:一段式状态机只选择一个状态标志位,这个状态标志位会在输入的决定下选择跳转到下一个状态还是维持原有状态,在每一个状态下检测状态标志位及输入来决定其状态的跳转及输出。其输出和状态的切换在一个always循环块中执行。
示例:
always @ (posedge clk) begin
case(FSM)
S0: begin
out<= ...;//输出
if(in...) FSM<=S1;//状态转移
else FSM <= S0;
end
S1: begin
out<= ...;//输出
if(in...) FSM<=S2;//状态转移
else FSM <= S1;
end
...
default:
endcase
end
优点:
- 单always块把组合逻辑和时序逻辑放在一个时序always块描述。输出时为寄存器输出,所以无毛刺
- 对于简单的状态机,把输入,转移,输出一起体现,比较直观
缺点: - 产生多余的触发器(因为把组合逻辑也放在时序逻辑中实现)
- 对于复杂状态机而言这种写法难以调试
不建议使用。
二段式状态机
第一个always块决定系统状态标志的自动跳转,第二个always块决定系统根据不同状态下的输入进行状态的跳转及输出。
//时序逻辑,描述从现态转移到次态
always @ (posedge clk) begin
current_state<=next_state;
end
//组合逻辑,包括转移条件以及状态内容(即输出)
always @ (*) begin
case(current_state)
S0:begin
out = ...;
if(in...) next_state = S1; //组合逻辑使用阻塞语句
else next_state = S0;
end
S1:begin
out = ...;
if(in...) next_state = S2; //组合逻辑使用阻塞语句
else next_state = S1;
end
...
endcase
end
优点:
- 二段式便于阅读,理解和维护,有利于综合器优化代码。
缺点: - 但是由于采用的是组合逻辑输出,容易产生毛刺
- 不利于约束,也不利于综合器和布局布线器实现高性能设计。
三段式状态机
通用mealy三段式状态机(建议实际工程中采用的结构)
//------采用独热码或格雷码或其他方式编码状态
parameter IDLE = ...
parameter S0 = ...
...
reg [x:0] curr_state;
reg [x:0] next_state;
//------每个时钟只产生一次状态变化
always @(posedge clk or posedge asy_rst)
begin
if(asy_rst) curr_state <= IDLE ;
else curr_state <= next_state;
end
//------产生的下一状态的组合逻辑
always @(*)
begin
next_state = 'bx;
case(curr_state)
IDLE: if(输入) next_state = S0 ;else...;
S0: if(输入) next_state = ...;
...
default: next_state = ...;
endcase
end
/************************时序或组合二选一***********************/
//------时序逻辑输出(比组合逻辑延时一个时钟)
always@(posedge clk or posedge asy_rst)
begin
if(asy_rst)out<= ...;
else
case(curr_state)
sO: if(...) out <= ...;
sO: if(...) out <= ...;
default: out <= ...;
endcase
end
// 如果是moore型则上面的判断条件通常不需要,out只与当前状态有关。
//------组合逻辑输出 采用 assign 或always
always @(*)
begin
if(asy_rst)out = ...;
else
case(curr_state)
sO: if(...) out = ...;
sO: if(...) out = ...;
default: out = ...;
endcase
end
三段式结构中,2个时序always块分别用来描述现态逻辑转移,及输出赋值。组合always块用于描述状态转移的条件。
优点:
- 这种结构是寄存器输出,输出无毛刺
- 而且代码更清晰易读,特别是对于复杂的状态机来说。
缺点:
- 消耗的面积更多点。
推荐使用三段式。