Exams/2012 q2fsm
两段状态机
module top_module (
input clk,
input reset, // Synchronous active-high reset
input w,
output z
);
reg [2:0] state,next_state;
parameter A=3'd0,B=3'd1,C=3'd2,D=3'd3,E=3'd4,F=3'd5;
always@(posedge clk )begin
if(reset)
state<=A;
else state<=next_state;
end
always@(*)begin
case(state)
A:begin
next_state<=(w = =0) ?A:B;
end
B:begin
next_state<=(w= =0) ?D:C;
end
C:begin
next_state<=(w= =0) ?D:E;
end
D:begin
next_state<=(w= =0) ?A:F;
end
E:begin
next_state<=(w= =0) ?D:E;
end
F:begin
next_state<=(w= =0) ?D:C;
end
endcase
end
assign z=(state= =E||state= =F)?1'b1:1'b0;
endmodule
两段式状态机采用两个always 模块实现状态机的功能,其中一个 always 采用同步时序逻辑描述状态转移,另一个 always 采用组合逻辑来判断状态条件转移。 虽然对于简单的代码我们没必要去比较一段式好还是两段式好,但是如果推荐肯定还是使用两段式的状态机,不过很时候笔者也偷懒,使用一段式的状态机。但是如果对于时序要求和状态机机有一定的规模的电路,还是用两段式的吧。
总之两段式状态机是推荐的状态机设计方法。
上述代码忘记了规定state位宽出错(易忽略)
reg [2:0] state,next_state;
三段状态机
module detect_3(
input clk_i,
input rst_n_i,
output out_o
);
reg out _r;
//状态声明和状态编码
reg [1:0] Current_state;
reg [1:0] Next_state;
parameter [1:0] S0=2'b00;
parameter [1:0] S1=2'b01;
parameter [1:0] S2=2'b10;
parameter [1:0] S3=2'b11;
//时序逻辑:描述状态转换
always@(posedge clk_i)
begin
if(!rst_n_i)
Current_state<=0;
else
Current_state<=Next_state;
end
//组合逻辑:描述下一状态
always@(*)
begin
case(Current_state)
S0:
Next_state = S1;
S1:
Next_state = S2;
S2:
Next_state = S3;
S3:
Next_state = Next_state;
default :
Next_state = S0;
endcase
end
//输出逻辑:让输出 out ,经过寄存器 out_r 锁存后输出,消除毛刺
always@(*)
begin
case(Current_state)
S0,S2:
out_r<=1'b0;
S1,S3:
out_r<=1'b1;
default :
out_r<=out_r;
endcase
end
assign out_o=out_r;
**三段式状态机在第一个always 模块采用同步时序逻辑方式描述状态转移,第二个 always 模块采用组合逻辑方式描述状态转移规律,第三个 always 描述电路的输出。**通常让输出信号经过寄存器缓存之后再输出,消除电路毛刺。这种状态机也是比较推崇的,主要是由于维护方便,组合逻辑与时序逻辑完全独立。
通过对比三种状态机的写法,可以发现,三段式的状态机翻译出来的原理图是最简洁最高效的编写方式,两段式也是很简洁的,但是比三段式差了一点点,而一段式是最差的表现。所以推荐是使用两段式以上的状态机。