状态机是fpga设计中极其重要的一种技巧,掌握状态机的写法可以使fpga的开发事半功倍。
下面记录一下状态机的基本知识理论。
实例:
三种状态机实现代码:
// 一段式状态机
module style1_fsm(i_clk, rst_n, i1, i2, o1, o2, err);
input i_clk, rst_n, i1, i2;
output o1, o2, err;
parameter [3:0] IDLE = 4'b0001,
S1 = 4'b0010,
S2 = 4'b0100,
ERROR= 4'b1000;
reg o1, o2, err;
reg [3:0] state;
always @(posedge i_clk or negedge rst_n)
begin
if(!rst_n) begin
state <= IDLE;
{o1, o2, err} <= 3'b000;
end
else
case(state)
IDLE: begin
if(!i1) begin
{o1, o2, err} <= 3'b000;
state <= IDLE;
end
if(i1 & i2) begin
{o1, o2, err} <= 3'b100;
state <= S1;
end
if(i1 & !i2) begin
{o1, o2, err} <= 3'b111;
state <= ERROR;
end
end
S1: begin
if(!i2) begin
{o1, o2, err} <= 3'b100;
state <= S1;
end
if(i1 & i2) begin
{o1, o2, err} <= 3'b010;
state <= S2;
end
if(!i1 & i2) begin
{o1, o2, err} <= 3'b111;
state <= ERROR;
end
end
S2: begin
if(i2) begin
{o1, o2, err} <= 3'b010;
state <= S2;
end
if(i1 & !i2) begin
{o1, o2, err} <= 3'b000;
state <= IDLE;
end
if(!i1 & !i2) begin
{o1, o2, err} <= 3'b111;
state <= ERROR;
end
end
ERROR: begin
if(i1) begin
{o1, o2, err} <= 3'b111;
state <= ERROR;
end
if(!i1) begin
{o1, o2, err} <= 3'b000;
state <= IDLE;
end
end
default:begin
{o1, o2, err} <= 3'b000;
state <= IDLE;
end
endcase
end
endmodule
// 两段式状态机
module style2_fsm(i_clk, rst_n, i1, i2, o1, o2, err);
input i_clk, rst_n, i1, i2;
output o1, o2, err;
parameter [3:0] IDLE = 4'b0001,
S1 = 4'b0010,
S2 = 4'b0100,
ERROR= 4'b1000;
reg o1, o2, err;
reg [3:0] curr_state, next_state;
always @(posedge i_clk or negedge rst_n) begin
if(!rst_n)
curr_state <= IDLE;
else
curr_state <= next_state;
end
always @(curr_state or i1 or i2) begin
case(curr_state)
IDLE: begin
if(!i1) begin
IDLE_OUT;
next_state = IDLE;
end
if(i1 & i2) begin
S1_OUT;
next_state = S1;
end
if(i1 & !i2) begin
ERROR_OUT;
next_state = ERROR;
end
end
S1: begin
if(!i2) begin
S1_OUT;
next_state = S1;
end
if(!i1 & i2) begin
ERROR_OUT;
next_state = ERROR;
end
if(i1 & i2) begin
S2_OUT;
next_state = S2;
end
end
S2: begin
if(i2) begin
S2_OUT;
next_state = S2;
end
if(i1 & !i2) begin
IDLE_OUT;
next_state = IDLE;
end
if(!i1 & !i2) begin
ERROR_OUT;
next_state = ERROR;
end
end
ERROR: begin
if(i1) begin
ERROR_OUT;
next_state = ERROR;
end
if(!i1) begin
IDLE_OUT;
next_state = IDLE;
end
end
default:begin
IDLE_OUT;
next_state <= IDLE;
end
endcase
end
task IDLE_OUT;
{o1, o2, err} = 3'b000;
endtask
task S1_OUT;
{o1, o2, err} = 3'b100;
endtask
task S2_OUT;
{o1, o2, err} = 3'b010;
endtask
task ERROR_OUT;
{o1, o2, err} = 3'b111;
endtask
endmodule
// 三段式状态机
module style3_fsm(i_clk, rst_n, i1, i2, o1, o2, err);
input i_clk, rst_n, i1, i2;
output o1, o2, err;
parameter [3:0] IDLE = 4'b0001,
S1 = 4'b0010,
S2 = 4'b0100,
ERROR= 4'b1000;
reg o1, o2, err;
reg [3:0] curr_state, next_state;
always @(posedge i_clk or negedge rst_n)
begin
if(!rst_n)
curr_state <= IDLE;
else
curr_state <= next_state;
end
always @(curr_state or i1 or i2)
begin
case(curr_state)
IDLE: begin
if(!i1) next_state = IDLE;
if(i1 & i2) next_state = S1;
if(i1 & !i2) next_state = ERROR;
end
S1: begin
if(!i2) next_state = S1;
if(i1 & i2) next_state = S2;
if(!i1 & i2) next_state = ERROR;
end
S2: begin
if(i2) next_state = S2;
if(i1 & !i2) next_state = IDLE;
if(!i1 & !i2) next_state = ERROR;
end
ERROR: begin
if(i1) next_state = ERROR;
if(!i1) next_state = IDLE;
end
default:begin
next_state = IDLE; // 不加这个default项 输出会一直是000!!!
end
endcase
end
always @(posedge i_clk or negedge rst_n)
begin
if(!rst_n)
{o1, o2, err} <= 3'b000;
else begin
case(next_state)
IDLE: {o1, o2, err} <= 3'b000;
S1: {o1, o2, err} <= 3'b100;
S2: {o1, o2, err} <= 3'b010;
ERROR: {o1, o2, err} <= 3'b111;
default:{o1, o2, err} <= 3'b000;//不加这个default 复位前信号都为不定值X
endcase
end
end
endmodule