概述
在复杂的流程控制中,控制状态是乱序的,使用状态机构架进行设计,可以很清晰的设计出复杂的状态转换关系,从而可以提高FPGA的设计效率,减少出错的可能。
状态机构架设计规则
状态机设计规则1:四段式写法
第一段:同步时序逻辑设计,次态到现态的迁移。
第二段:组合逻辑设计:状态转移转移条件判断。
第三段:定义转移添加。
第四段:根据状态设计输出。
状态机设计规则2:四段式状态机的第一段写法不变。
状态机设计规则3:状态机转移条件的命名规则是xx_to_xx_start形式,表示从某个状态转换到另一个状态。
状态机设计规则4:状态转移条件,用assign产生变换条件时,必须加上当前状态。
状态机设计规则5:状态机不变保持时使用 state_n = state_c。
verilog实现四个状态控制两个led的状态机设计如下:
第一段:
module ztj( clk , rst_n ,
led1 , led2
);
input clk;
input rst_n;
output reg led1;
output reg led2;
parameter S0 = 3'd0,
S1 = 3'd1,
S2 = 3'd2,
S3 = 3'd3;
//状态码
reg [2:0] state_c; //现态
reg [2:0] state_n; //次态
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
state_c <= S0; //默认状态
else
state_c <= state_n; //次态转换到现态
end
第二段:
always @( * ) begin
case( state_c )
S0 : begin
if( s0_to_s1_start)
state_n = S1;
else
state_n = state_c;
end
S1 : begin
if( s1_to_s2_start)
state_n = S2;
else
state_n = state_c;
end
S2 : begin
if( s2_to_s3_start)
state_n = S3;
else
state_n = state_c;
end
S3 : begin
if( s3_to_s0_start)
state_n = S0;
else
state_n = state_c;
end
default :
state_n = S0;
endcase
end
第三段:
wire s0_to_s1_start;
wire s1_to_s2_start;
wire s2_to_s3_start;
wire s3_to_s0_start;
assign s0_to_s1_start = (state_c == S0) && end_cnt1;
assign s1_to_s2_start = (state_c == S1) && end_cnt1;
assign s2_to_s3_start = (state_c == S2) && end_cnt1;
assign s3_to_s0_start = (state_c == S3) && end_cnt1;
第四段:
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
led1 <= 0;
else if( state_c == S0 )
led1 <= 0;
else if( state_c == S1 )
led1 <= 1;
else if( state_c == S2 )
led1 <= 0;
else if( state_c == S3 )
led1 <= 1;
end
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
led2 <= 0;
else if( state_c == S0 )
led2 <= 0;
else if( state_c == S1 )
led2 <= 0;
else if( state_c == S2 )
led2 <= 1;
else if( state_c == S3 )
led2 <= 1;
end
//计数器
reg [15:0] cnt0; //计数器
wire add_cnt0; //加1条件
wire end_cnt0; //结束条件
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt0 <= 16'd0;
else if( add_cnt0 ) begin
if( end_cnt0 )
cnt0 <= 16'd0;
else
cnt0 <= cnt0 +1'b1;
end
end
assign add_cnt0 = 1'b1;
assign end_cnt0 = add_cnt0 && cnt0 == 50000-1;
//------------
reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt1 <= 8'd0;
else if( add_cnt1 ) begin
if( end_cnt1 )
cnt1 <= 8'd0;
else
cnt1 <= cnt1 + 1'b1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1 == 10-1;