三段式状态机,第一段描述状态的转移。
always @(posedge clk or posedge rst) begin
if(rst==1'b1)begin
current_state<=PWR_ON;
end
else begin
current_state<=next_state;
end
end
第二段使用组合逻辑描述状态的转移过程。笔者在第二段状态机犯了多个错误。铭记警醒,以供后期注意。
1.组合逻辑内多信号的赋值使用非阻塞赋值<=,错误。应该使用阻塞赋值=。
2.第二段组合逻辑掺杂进来一些其他控制信号,调试过程中问题百出,正确的方法应该是本段只描述状态的转移,其他信号在外部使用always赋值操作。
3.组合逻辑里绝对不能出现不全的ifelse结构,否则软件会报警告,无法分析主时钟与某一奇怪网表信号的时钟关系,原因是不全的ifelse架构导致latch产生,所以时序无法分析。PWR_ON状态里出现next_state<=PWR_ON,这种赋值不是latch,因为给next_state了一个确定的值。而组合逻辑ifelse不全将导致latch生成。
always @(*) begin
case(current_state)
PWR_ON:begin
if(power_on_end==1'b1)begin
next_state=JUDE;
reboot_pwr_on_flag=1'b0;
end
else begin
next_state=PWR_ON;
reboot_pwr_on_flag=1'b1;
end
re_pwr_on_dly_en=1'b0;
end
JUDE:begin
re_pwr_on_dly_en=1'b0;if(reboot_flag==1'b1)begin
next_state=SHUT_DOWN;
reboot_pwr_on_flag=1'b1;
end
elseif(shut_down_flag==1'b1)begin
next_state=SHUT_DOWN;
reboot_pwr_on_flag=1'b0;
end
else begin
next_state=JUDE;
reboot_pwr_on_flag=1'b0;
end
end
SHUT_DOWN:begin
re_pwr_on_dly_en=1'b0;if(shut_down_end==1'b1)begin
if(reboot_pwr_on_flag==1'b1)begin
next_state=RE_PWR_ON1;
end
else begin
next_state=JUDE;
end
end
else begin
next_state=SHUT_DOWN;
end
end
RE_PWR_ON1:begin
next_state=RE_PWR_ON2;
re_pwr_on_dly_en=1'b1;
reboot_pwr_on_flag=1'b1;
end
RE_PWR_ON2:begin
re_pwr_on_dly_en=1'b0;
reboot_pwr_on_flag=1'b1;if(re_pwr_on_dly_end_500ms==1'b1)begin
next_state=PWR_ON;
end
else begin
next_state=RE_PWR_ON2;
end
end
default:begin
next_state=JUDE;
re_pwr_on_dly_en=1'b0;
reboot_pwr_on_flag=1'b0;
end
endcase
end
修改后的代码结构如下:在第二段状态机内只描述状态的转移过程,没有描述具体信号的情况,输出信号放在了第三段。
always @(posedge clk or posedge rst) begin
if(rst==1'b1)begin
current_state<=PWR_ON;
end
else begin
current_state<=next_state;
end
end
always @(*) begin
case(current_state)
PWR_ON:begin
if(power_on_end==1'b1)begin
next_state=JUDE;
end
else begin
next_state=PWR_ON;
end
end
JUDE:begin
if(pwr_on_flag==1'b1)begin
next_state=PWR_ON;
end
elseif(reboot_flag==1'b1)begin
next_state=SHUT_DOWN;
end
elseif(shut_down_flag==1'b1)begin
next_state=SHUT_DOWN;
end
else begin
next_state=JUDE;
end
end
SHUT_DOWN:begin
if(shut_down_end==1'b1)begin
next_state=JUDE;
end
else begin
next_state=SHUT_DOWN;
end
end
default:begin
next_state=JUDE;
end
endcase
end