三段式状态机

最近在做项目时,一开始用一段式状态机编写代码。事后觉得太冗杂,然后用纯逻辑进行编辑,并且未进行流程框图的描述,仅仅凭脑子写到哪是哪。这样十分不妥。

所以我希望以后做项目要用状态机来进行写控制逻辑,并且要在写代码前准确列出各状态,这样是方便更改程序的。那么就聊聊状态机。

关于FSM的写法按照always块的个数来划分可以分为一段式(一个always块)、两段式状态机(两个always块)、三段式状态机(三个always块)。

一段式状态机:既描述状态的转移,也描述状态的输出;描述大型状态比较烦,不方便修改,臃肿,优点是逻辑清晰

二段式状态机:第一段时序逻辑描述状态转移,第二段用组合逻辑描述状态的输出;结构和理想的理论模型吻合,精简,但是第二段是组合逻辑描述的,有些情况无法准确描述,比如输出时需要类似计数的累加情况,那么在组合逻辑当中会产生自迭代(在组合逻辑电路里严格禁止)。并且输出用组合逻辑的话有产生毛刺的风险,所以也不推荐。二段式在组合逻辑特别复杂时适用,但要注意需在后面加一个触发器以消除组合逻辑对输出产生的毛刺。三段式没有这个问题,由于第三个always会生成触发器。

三段式状态机:
第一段时序逻辑描述状态转移,
第二段使用组合逻辑判断状态转移条件,描述状态转移规律,
第三段状态机描述状态输出(可以使用组合逻辑,也可以用时序逻辑)。

三段式状态机具有以下优点:
(1) 三段式状态机可以清晰完整的显示出状态机的结构,
(2) 可以清晰的将状态图转化为verilog代码,
(3) 代码清晰,降低编写维护复杂度,
三段式状态机_第1张图片
Moore:输出只是和当前状态有关,而与输入无关
Mealy: 输出不仅和当前状态有关,还与输入有关

按照三段式状态机进行分析,第一个框图是描述状态寄存器,为时序逻辑,后两个框图描述转移和输出,为组合逻辑。
三段式状态机对应的代码模版:

第一个always块,描述对应当前状态的状态寄存器,非阻塞赋值:

always @ (posedge clk)begin
		if(rst)begin
			current_state <= idle;
		end else begin
			current_state <= next_state;
		end
end

第二个always块,描述下一状态的状态寄存器,阻塞赋值:

always @ (*)begin
		next_state = idle;
		case(current_state)
				idle:begin
					if(...)next_state =...;
					else   next_state =...;
				end
				.
				.
				.
				default:	next_state =...;
		endcase
end

第三个always块,描述输出,阻塞赋值:

always @ (*)begin
		if(rst)output = ...;
		else begin
			case(current_state)
					s1:begin
						output = ...;
					end
					.
					.
					.
					default:	
						output = ...;
			endcase
		end
end

对于第三个always块,在网上查到有些是使用时序逻辑,非阻塞赋值,使用next_state进行状态判断,对应代码如下:

always @ (posedge clk)begin
		if(rst)output <= ...;
		else begin
			case(next_state)
					s1:begin
						output <= ...;
					end
					.
					.
					.
					default:	output <= ...;
			endcase
		end
end

你可能感兴趣的:(FPGA,IP核,数字设计基础,Vivado,fpga开发)