FPGA學習筆記(四)——狀態機設計思路

1、狀態機工作原理

狀態機是一種能夠描述具有邏輯順序和時序順序的事件的方法,特別適合描述那些存在先後順序以及其它規律性事件。狀態機是組合邏輯和寄存器邏輯的特殊組合,一般包括兩個部分:組合邏輯部分和寄存器邏輯部分;寄存器用於存儲狀態,組合電路用於狀態譯碼和產生輸出信號。狀態機的下一個狀態及輸出不僅與輸入信號有關,還與寄存器當前狀態有關,其基本要素有三個:狀態、輸出和輸入。

(1)狀態

狀態也叫狀態變量。在邏輯設計中,使用狀態劃分邏輯順序和時序規律。例如要設計一個交通燈控制器,可以允許通行、慢行和禁止通行作爲狀態;設計一個電梯控制器,每層就是一個狀態等等。

(2)輸入

指狀態機中進入每個狀態的條件,有的狀態機沒有輸入條件,其中的狀態轉移較爲簡單;有的狀態機有輸入條件,當某個輸入條件存在時才能轉移到相應的狀態。例如,交通燈控制器就沒有輸入條件,狀態隨着時間的改變自動跳轉;電梯控制器是存在輸入的,每一層的上下按鍵以及電梯內的層數選擇按鍵都是輸入,會對電梯的下一個狀態產生影響。

(3)輸出

輸出指在某一個狀態時特定發生的事件。例如,交通燈控制器在允許通行狀態輸出綠色,緩行狀態輸出黃色,禁止通行狀態輸出紅色;電梯控制器在運行時一直會輸出當前所在層數以及當前運行方向(上升或下降)。

2、例子

Welcom

64個字符長度的序列

fagpaljkhdwiernggaolWelcom

從序列中檢測出總共有多少個需要檢測的序列Welcom。

//時序邏輯
module FSM(
	clk,
	rst_n,
	dv,//數據開始有效信號,開始檢測信號
	data,//數據何時傳進來,何時結束。即數據何時有效
	num,//Welcon個數
	get_flag//數據結束信號
);
	input clk;
	input rst_n;
	input dv;
	input [7:0] data;//一個字符,8位
	output [3:0] num;
	output get_flag;
	
	reg [3:0] cnt;//計數,Welcom的個數
	//狀態機
	//定義狀態
	reg [2:0] state;
	
	//參數法
	localparam CHECK_W = 3'd0;
	localparam CHECK_E = 3'd1;
	localparam CHECK_L = 3'd2;
	localparam CHECK_C = 3'd3;
	localparam CHECK_O = 3'd4;
	localparam CHECK_M = 3'd5;
	always@(posedge clk or negedge rst_n)
	if(!rst_n)begin
		state <= CHECK_W;
		cnt <= 4'd0;
	end	
	else if(dv) begin
		case(state)
			CHECK_W://檢測W
				if(data == "W")
					state <= CHECK_E;
				else
					state <= CHECK_W;//沒有檢測到'W',就保持原有狀態
			CHECK_E://檢測e
				if(data == "e")
					state <= CHECK_L;
				else if(data == "W")//不是'e',如果是'W',要重新檢測
					state <= CHECK_E;
				else
					state <= CHECK_W;//沒有檢測到'e',就跳轉到新狀態
			CHECK_L://檢測'l'
				if(data == "l")
					state <= CHECK_C;
				else if(data == "W")//不是'e',如果是'W',要重新檢測
					state <= CHECK_E;
				else
					state <= CHECK_W;//沒有檢測到'l',就跳轉到新狀態
			CHECK_C://檢測'c'
				if(data == "c")
					state <= CHECK_O;
				else if(data == "W")//不是'e',如果是'W',要重新檢測
					state <= CHECK_E;
				else
					state <= CHECK_W;//沒有檢測到'c',就跳轉到新狀態
			CHECK_O://檢測'o'
				if(data == "o")
					state <= CHECK_O;
				else if(data == "W")//不是'e',如果是'W',要重新檢測
					state <= CHECK_E;
				else
					state <= CHECK_W;//沒有檢測到'o',就跳轉到新狀態
			CHECK_M://檢測'm'
				if(data == "m")begin
					state <= CHECK_W;
					cnt <= cnt + 1'd1;
				end
				else if(data == "W")//不是'e',如果是'W',要重新檢測
					state <= CHECK_E;
				else
					state <= CHECK_W;//沒有檢測到'm',就跳轉到新狀態
			default:state <= CHECK_W;
		endcase
	end
	else
		state <= CHECK_W;	 

endmodule	

3、測試文件

`timescale 1ns/1ns
`define clk_period 20

module FSM_Welcome;

	reg clk;
	reg rst_n;
	wire [7:0]data;
	reg start;
	
	wire [2:0]num;
	wire flag;
	
	wire [511:0]data_tmp;
	reg [511:0]data_reg;
	assign data_tmp = "abcdeWelcomehijkWelcomedcba";
	
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
		data_reg <= 0;
	else if(start)
		data_reg <= data_reg << 8;
	else 
		data_reg <= data_tmp;
		
	assign data = data_reg[511:504];
	
	FSM_Welcome FSM_Welcome(
		.clk(clk),
		.rst_n(rst_n),
		.data(data),
		.start(start),
		.num(num),
		.flag(flag)
	);
	
	initial clk = 1;
	always#(`clk_period/2)clk = ~clk;
	
	initial begin
		rst_n = 0;
		start = 0; 
		#(`clk_period*20)
		rst_n = 1;
		#(`clk_period*10)
		start = 1;
		#(`clk_period*64)
		#200;
		$stop;
	end 

endmodule 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章