1. 程式人生 > >【FPGA】Verilog狀態機設計

【FPGA】Verilog狀態機設計

狀態機是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