有限状态机(finite statemachine,FSM)广泛应用于数字系统的控制器设计中.由于设计方法不同,综合出来的电路结构、速度、面积和时延特性都会有很大的差别, 甚至某些臃肿的电路还会产生难以预料的问题.
1.“一段式”
特点:将当前状态向量和输出向量用同一时序always块进行描述。
缺点:代码冗长,不易修改和调试,可维护性较差且占用资源多;通过case语句对输出向量的赋值应是下一个状态的输出,这点容易出错;状态向量和输出向量都是由寄存器逻辑实现,面积较大;不能实现异步mealy有限状态机。
优点:寄存器输出,输出向量不会产生毛刺。
结构:

例程:
moduleFSM(
				clk,
				rst_n,
				data_cap,//
				data_low,
				out_flow
				);
				
	inputclk,rst_n;
	input[7:0]data_cap,data_low;//大写,小写字母数据流
	
	outputreg[7:0]out_flow;
	
	reg[7:0]state;
	
	localparam//独热码
		CHECK_I=8'b0000_0001,
		CHECK_L=8'b0000_0010,
		CHECK_o1=8'b0000_0100,
		CHECK_v=8'b0000_1000,
		CHECK_e=8'b0001_0000,
		CHECK_Y=8'b0010_0000,
		CHECK_o2=8'b0100_0000,
		CHECK_u=8'b1000_0000;
		
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		out_flow<=0;
		state<=CHECK_I;
	end
	elsebegin
		case(state)
			CHECK_I	:	if(data_cap=="I")begin
								state<=CHECK_L;
								out_flow<=data_cap;
							end
							else
								state<=CHECK_I;
			
			CHECK_L	:	if(data_cap=="L")begin
								state<=CHECK_o1;
								out_flow<=data_cap;
							end
							else
								state<=CHECK_L;
			
			CHECK_o1	:	if(data_low=="o")begin
								state<=CHECK_v;
								out_flow<=data_low;
							end
							else
								state<=CHECK_o1;
			
			CHECK_v	:	if(data_low=="v")begin
								state<=CHECK_e;
								out_flow<=data_low;
							end
							else
								state<=CHECK_v;
			
			CHECK_e	:	if(data_low=="e")begin
								state<=CHECK_Y;
								out_flow<=data_low;
							end
							else
								state<=CHECK_e;
			
			CHECK_Y	:	if(data_cap=="Y")begin
								state<=CHECK_o2;
								out_flow<=data_cap;
							end
							else
								state<=CHECK_Y;
			
			CHECK_o2	:	if(data_low=="o")begin
								state<=CHECK_u;
								out_flow<=data_low;
							end
							else
								state<=CHECK_o2;
			
			CHECK_u	:	if(data_low=="u")begin
								state<=CHECK_I;
								out_flow<=data_low;
							end
							else
								state<=CHECK_u;
			
			default	:	begin
								out_flow<=0;
								state<=CHECK_I;
							end
		endcase	
	end
	
endmodule
RTL:

资源使用:

仿真效果:

2.“两段式”
特点:(第一段)一个时序always块给当前状态向量赋值,(第二段)一个组合always块给下一个状态向量和输出向量赋值。
缺点:(1)组合逻辑输出会使输出向量产生毛刺; 
(2)从速度角度而言,由于这种状态机的输出向量必须由状态向量经译码得到,因此加大了从状态向量到输出向量的延时。 
(3)从综合角度而言,组合输出消耗了一部分时钟周期,即增加了由它驱动的下一个模块的输入延时。
结构:

例程:
moduleFSM(
				clk,
				rst_n,
				data_cap,//
				data_low,
				out_flow
				);
				
	inputclk,rst_n;
	input[7:0]data_cap,data_low;//大写,小写字母数据流
	
	outputreg[7:0]out_flow;
	
	reg[7:0]state,NS;
	
	localparam//独热码
		CHECK_I=8'b0000_0001,
		CHECK_L=8'b0000_0010,
		CHECK_o1=8'b0000_0100,
		CHECK_v=8'b0000_1000,
		CHECK_e=8'b0001_0000,
		CHECK_Y=8'b0010_0000,
		CHECK_o2=8'b0100_0000,
		CHECK_u=8'b1000_0000;
	
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		state<=CHECK_I;
	end
	elsebegin
		state<=NS;
	end
	
	always@(rst_norstateordata_capordata_low)
	begin
		NS=8'bx;
		out_flow<=8'bx;
		case(state)
			CHECK_I	:	if(data_cap=="I")begin
								NS<=CHECK_L;
								out_flow<=data_cap;
							end
							else
								NS<=CHECK_I;
			
			CHECK_L	:	if(data_cap=="L")begin
								NS<=CHECK_o1;
								out_flow<=data_cap;
							end
							else
								NS<=CHECK_L;
			
			CHECK_o1	:	if(data_low=="o")begin
								NS<=CHECK_v;
								out_flow<=data_low;
							end
							else
								NS<=CHECK_o1;
			
			CHECK_v	:	if(data_low=="v")begin
								NS<=CHECK_e;
								out_flow<=data_low;
							end
							else
								NS<=CHECK_v;
			
			CHECK_e	:	if(data_low=="e")begin
								NS<=CHECK_Y;
								out_flow<=data_low;
							end
							else
								NS<=CHECK_e;
			
			CHECK_Y	:	if(data_cap=="Y")begin
								NS<=CHECK_o2;
								out_flow<=data_cap;
							end
							else
								NS<=CHECK_Y;
			
			CHECK_o2	:	if(data_low=="o")begin
								NS<=CHECK_u;
								out_flow<=data_low;
							end
							else
								NS<=CHECK_o2;
			
			CHECK_u	:	if(data_low=="u")begin
								NS<=CHECK_I;
								out_flow<=data_low;
							end
							else
								NS<=CHECK_u;
			
			default	:	begin
								out_flow<=8'bx;
								NS<=CHECK_I;
							end
		endcase	
	end
	
	
endmodule
RTL:

资源占用:

仿真:


3.“三段式”
特点:两个时序always块,分别产生当前状态向量和输出向量,再用一个组合逻辑always块产生下一个状态向量。 
代码主要包含以下三部分:
[1] 状态转移部分(时序逻辑)
[2] 状态转移条件部分(即产生下个状态向量的模块,组合逻辑)
[3] 输出逻辑部分(时序逻辑)
优点:三段式描述方法虽然代码结构复杂了一些,但是换来的优势是:使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。
结构:

例程:
moduleFSM(
				clk,
				rst_n,
				data_cap,//
				data_low,
				out_flow
				);
				
	inputclk,rst_n;
	input[7:0]data_cap,data_low;//大写,小写字母数据流
	
	outputreg[7:0]out_flow;
	
	reg[7:0]state,NS;
	
	localparam//独热码
		CHECK_I=8'b0000_0001,
		CHECK_L=8'b0000_0010,
		CHECK_o1=8'b0000_0100,
		CHECK_v=8'b0000_1000,
		CHECK_e=8'b0001_0000,
		CHECK_Y=8'b0010_0000,
		CHECK_o2=8'b0100_0000,
		CHECK_u=8'b1000_0000;
	
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		state<=CHECK_I;
	end
	elsebegin
		state<=NS;
	end
	
	always@(rst_norstateordata_capordata_low)
	begin
		NS=8'bx;
		case(state)
			CHECK_I	:	if(data_cap=="I")
								NS<=CHECK_L;
							else
								NS<=CHECK_I;
			
			CHECK_L	:	if(data_cap=="L")
								NS<=CHECK_o1;
							else
								NS<=CHECK_L;
			
			CHECK_o1:	if(data_low=="o")
								NS<=CHECK_v;
							else
								NS<=CHECK_o1;
			
			CHECK_v	:	if(data_low=="v")
								NS<=CHECK_e;
							else
								NS<=CHECK_v;
			
			CHECK_e	:	if(data_low=="e")
								NS<=CHECK_Y;
							else
								NS<=CHECK_e;
			
			CHECK_Y	:	if(data_cap=="Y")
								NS<=CHECK_o2;
							else
								NS<=CHECK_Y;
			
			CHECK_o2:	if(data_low=="o")
								NS<=CHECK_u;
							else
								NS<=CHECK_o2;
			
			CHECK_u	:	if(data_low=="u")
								NS<=CHECK_I;
							else
								NS<=CHECK_u;
			
			default	:	NS<=CHECK_I;
		endcase	
	end
	
	always@(posedgeclkornegedgerst_n)
	if(!rst_n)begin
		out_flow<=8'b0;
	end
	elsebegin
		case(NS)
			CHECK_I	:	out_flow<="I";//I
CHECK_L	:	out_flow<="L";//L
CHECK_o1:	out_flow<="o";//o
		
CHECK_v	:	out_flow<="v";//v
CHECK_e	:	out_flow<="e";//e
CHECK_Y	:	out_flow<="Y";//Y
CHECK_o2:	out_flow<="o";//o
CHECK_u	:	out_flow<="u";//u
			
		endcase
	end
endmodule
RTL:

资源占用:

以上的仿真代码:
`timescale1ns/1ns
`defineclock_period20
moduleFSM_tb;
	
	regclk;
	regrst_n;
	reg[7:0]data_cap,data_low;
	
	wire[7:0]out_flow;	
	
	FSMFSM(
		.clk(clk),
		.rst_n(rst_n),
		.data_cap(data_cap),//
		.data_low(data_low),
		.out_flow(out_flow)
		);
	
	always@(posedgeclk)
	begin
		#(`clock_period)data_cap=65+{$random}%26;
		#(`clock_period)data_low=97+{$random}%26;
	end
	
		
	initialclk=1;
	always#(`clock_period/2)clk=~clk;
	
	initialbegin
		rst_n=0;
		//ASCII=0;
		#(`clock_period*5);
		rst_n=1;
		#(`clock_period*500);
		//foreverbegin
		$stop;	
	end
endmodule
一般而言,推荐的FSM 描述方法是后两种。这是因为:FSM和其他设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺。状态机实现后,一般来说,状态转移部分是同步时序电路而状态的转移条件的判断是组合逻辑。 第二种描述方法同第一种描述方法相比,将同步时序和组合逻辑分别放到不同的always模块中实现,这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。在第二种方式的描述中,描述当前状态的输出用组合逻辑实现,组合逻辑很容易产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计。
为了使FSM 描述清晰简介,易于维护,易于附加时序约束,使综合器和布局布线器更好的优化设计,推荐使用两段式FSM 描述方法。