夏宇闻《Verilog数字系统设计教程》 - 第12章 同步状态机的原理、结构和设计

该章节对状态机的初步理解有所帮助,但更多干货和实际编码还需要再多学习和参考一下

第12章 同步状态机的原理、结构和设计

概述

可综合的Verilog HDL和VHDL的语法只是它们各自语言的一个子集。由于寄存器传输级(RTL)描述的是以时序逻辑抽象所得到的有限状态机为依据,所以,把一个时序逻辑抽象成一个同步有限状态机是设计可综合风格的Verilog VHDL模块的关键。

12.1 状态机的结构

下图是数字电路设计中常用的时钟同步状态机的结构(Mealy状态机)。其中,

状态寄存器是由一组触发器组成,用来记忆状态机当前所处的状态。如果状态寄存器由n个触发器组成,这个状态机最多可以记忆 2 n 2^n 2n个状态。

所有的触发器的时钟端都连接在一个共同的时钟信号上,所以状态的改变只可能发生在时钟的跳变沿上。

下一个状态 = F(当前状态,输入信号)
输出信号 = G(当前状态,输入信号)

12.2 Mealy状态机和Moore状态机的不同点

Mealy状态机:时序逻辑的输出不但取决于状态还取决于输入;
Moore状态机:时序逻辑电路的输出只取决于当前状态,即 输出信号 = G(当前状态)
,如下图所示

参考其他博客Verilog状态机,补充Mealy状态机和Moore状态机区别:

Moore 型状态机的输出只与当前状态有关,与当前输入无关。输出会在一个完整的时钟周期内保持稳定,即使此时输入信号有变化,输出也不会变化。输入对输出的影响要到下一个时钟周期才能反映出来。这也是 Moore 型状态机的一个重要特点:输入与输出是隔离开来的。

Mealy 型状态机的输出,不仅与当前状态有关,还取决于当前的输入信号。Mealy 型状态机的输出是在输入信号变化以后立刻发生变化,且输入变化可能出现在任何状态的时钟周期内。因此,同种逻辑下,Mealy 型状态机输出对输入的响应会比 Moore 型状态机早一个时钟周期

12.3 如何用Verilog来描述可综合的状态机

在Verilog HDL中可以用多种方法来描述有限状态机,最常用的方法是用always语句和case语句

下图所示的状态转移图表示了一个简单的4状态的有限状态机,同步时钟是clk,输入信号是A和Reset,输出信号是K2和K1

整个章节使用该案例贯穿讲解不同的编码方法,重点是状态机的编码等,但参考代码中关于不同状态时K2和K1的输出完全没看明白,不知道是不是写错了,还是我理解问题。

12.3.1 用可综合Verilog模块设计状态机的典型办法

module fsm(Clock, Reset, A, K2, K1, state);
	input Clock, Reset, A;
	output K2, K1;
	output [1:0] sate;
	reg K2, K1;
	reg [1:0] state;
	parameter 	Idle 	= 	2'b00;
	parameter	Start 	= 	2'b01;
	parameter	Stop 	= 	2'b10;
	parameter	Clear 	= 	2'b11;

	always @(posedge Clock)
		if(!Reset) 
			begin
				state <= Idle;
				K2 <= 0;
				K1 <= 0;
			end
		else
			case(state)
				Idle: 
					if(A) begin
						state <= Start;
						K1 <= 0;
					end
					else begin
						state <= Idle;
						K2 <= 0;
						K1 <= 0;
					end
				Start:
					if(!A) begin
						state <= Stop;
					end
					else begin
						state <= Start;
					end
				Stop:
					if(A) begin
						state <= Clear;
						K2 <= 1;
					end
					else begin
						state  <= Stop;
						// 问题:在Stop和Clear状态时的保持,为啥K2和K1是这个输出,看图看不出来
						// K2 <= 0;
						// K1 <= 0;
					end
				Clear:
					if(!A) begin
						state <= Idle;
						K2 <= 0;
						K1 <= 0;
					end
					else begin
						state <= Clear;
						// K2 <= 0;
						// K1 <= 1;
					end
				default: state <= 2'bxx;
			endcase
endmodule

12.3.2 用可综合Verilog模块设计、用独热码表示状态的状态机

与上述例子不同的是状态的编码模式,采用独热编码,其他一致部分代码一致

parameter 	Idle 	= 	4'b1000,
			Start 	= 	4'b0100,
			Stop 	= 	4'b0010,
			Clear 	=	4'b0001;

对于FPGA实现的有限状态机建议采用独热码,因为虽然独热编码多用了两个触发器,但所用组合电路可省一些,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。

采用独热编码后有了多余的状态,就有一些不可到达的状态。为此,在case语句的最后需要增加default分支项。这可以用默认项表示该项,也可以用确定项表示,以确定回到Idle状态。一般综合器都可以通过综合指令的控制来合理地处理默认项。

12.3.3 用可综合Verilog模块设计、由输出指定的码表示状态的状态机

把输出直接指定为状态码:把状态码的指定与状态机控制的输出联系起来,把状态的变化直接用作输出,这样做可以提高输出信号的开关速度并节省电路器件。但这种方法的缺点是,开关的维持时间必须与状态的维持时间一致(如果要完全实现上面两例子的开关输出波形,需要增加状态才能实现)这种设计方法常用在高速状态机中

module fsm(Clock, Reset, A, K2, K1, state);
	input	Clock, Reset, A;
	output	K2, K1;
	output	[4:0]	state;
	reg		[4:0]	state;
	assign K2 = state[4];	// 把状态变量的最高位用作输出K2
	assign K1 = state[0];
	parameter
	// -------- K2_i_j_K1 -------- output coded state assignment
	Idle		=	5'b0_0_0_0_0,
	Start		=	5'b0_0_0_1_0,
	Stop		=	5'b0_0_1_0_0,
	StopToClear	=	5'b1_1_0_0_0,
	Clear		=	5'b0_1_0_1_0,
	ClearToIdle	=	5'b0_0_1_1_1;

	always @(posedge Clock)
		if(! Reset)
			begin
				// state <= Zero;		??? Zero啥,哪来的Zero
				state <= Idle;
			end
		else
			case(state)
				Idle: 
					if(A)
						state <= Start;
					else
						state <= Idle;
				Start:
					if(A)
						state <= Stop;
					else
						state <= Start;
				Stop:
					if(A)
						state <= StopToClear;
					else
						state <= Stop;
				StopToClear: state <= Clear;	// 保持输出
				Clear:
					if(!A)
						state <= ClearToIdle;
					else
						state <= Clear;
				ClearToIdle: state <= Idle;		// 保持输出
				default: state <= Idle;
			endcase
endmodule

12.3.4 用可综合Verilog模块设计复杂的多输出状态机时常用的方法

在比较复杂的状态机设计过程中,往往把状态的变化与输出开关的控制分成两部分来考虑。为了调试方便,还常常把每一个输出开关写成一个个独立的always组合块

module fsm(Clock, Reset, A, K2, K1);
	input Clock, Reset, A;
	output K2, K1;
	reg K2, K1;
	reg [1:0] state, nextstate;

	parameter
		Idle	=	2'b00;
		Start	=	2'b01;
		Stop	=	2'b10;
		Clear	=	2'b11;
	// -------- 每一个时钟沿产生一次可能的状态变化 --------
	always @(posedge Clock)
		if(!Reset)
			state	<=	Idle;
		else
			state	<=	nextstate;
	// -----------------------------------------------
	// -------- 产生下一状态的组合逻辑 --------
	always @(state or A)
		case(state)
			Idle: 
				if(A)
					nextstate	=	Start;
				else
					nextstate	=	Idle;
			Start: 
				if(!A)
					nextstate	=	Stop;
				else
					nextstate	=	Start;		
			Stop: 
				if(A)
					nextstate	=	Clear;
				else
					nextstate	=	Stop;
			Clear: 
				if(!A)
					nextstate	=	Idle;
				else
					nextstate	=	Clear;
			default:
				nextstate	=	2'bxx;
		encase
	// -----------------------------------------------
	// -------- 产生输出K1的组合逻辑 --------
	always @(state or Reset or A)
		if(!Reset) K1 = 0;
		else
			if(state == Clear && !A)	// 从Clear转向Idle
				K1 = 1;
			else K1 = 0;
	// -------- 产生输出K2的组合逻辑 --------
	always @(state or Reset or A)
		if(!Reset) K2 = 0;
		else
			if(state == Stop && A)	// 从Stop转向Clear
				K2 = 1;
			else K2 = 0;	
	// -----------------------------------------------
endmodule

上述代码案例,遵循的是三段式编写规范,这种风格描述比较适合大型的状态机,查错和修改比较容易,Synopsys公司的综合器建议使用这种风格来描述状态机

上述4个例子是同一状态机的4种不同的Verilog HDL模型,它们都是可综合的,在设计复杂程度不同的状态机时有它们各自的优势。如用不同的综合器对这4个例子进行综合,综合出的逻辑电路可能会有些不同,但逻辑功能是相同的

如下为测试不同风格状态机测试模块以供参考

`timescale 1ns/1ns
modult t;
	reg 	a;
	reg		clock,	rst;
	wire	k2,		k1;

	initial begin					// initial 常用于仿真时信号的给出
		a = 0;
		rst = 1;					// 给复位信号变量赋初始值
		clock = 0;					// 给时钟变量赋初始值
		#22		rst = 0;			// 使复位信号有效
		#133	rst = 1;			// 经过多个周期后使复位信号无效
	end
	
	always #50	clock = ~clock;	// 产生周期性的时钟
	always @(posedge clock) begin	// 在每次时钟正跳变沿时刻产生不同的a
		#30 a = {$ random} % 2;		// 每次a是0还是1是随机的
		#(3 * 50 + 12);				// a的值维持一段时间
	end
	
	initial begin
		#100000 $stop;				// 系统任务,暂停仿真以便观察仿真波形
	end

	// -------------- 调用被测试模块 t. m -----------------
	fsm m(.Clock(clock), .Reset(rst), .A(a), .K2(k2), .K1(k1));
	
endmodule

小结

有限状态机设计的一般步骤:

(1)逻辑抽象,得出状态转换图:就是把给出的一个实际逻辑关系表示为时序逻辑函数,可以用状态转换表来描述,也可以用状态转换图来描述。这就需要:
① 分析给定的逻辑问題,确定输入变量、输出变量以及电路的状态数。通常是取原因(或条件)作为输入变量,取结果作为输出变量。
② 定义输入、输出逻辑状态的含意,并将电路状态顺序编号。
③ 按照要求列出电路的状态转换表或画出状态转换图。
这样,就把给定的逻辑问题抽象到一个时序逻辑函数了。

(2)状态化简:如果在状态较换图中出现这样两个状态,它们在相同的输入下转换到同一状态去,并得到一样的输出,则称为等价状态。显然等价状态是重复的,可以合井为一个电路的状态数越少,存储电路也就越简单。状态化简的目的就在于将等价状态尽可能地合并,以得到最简的状态转换图。

(3)状态分配:状态分配又称状态编码。通常有很多编码方法,编码方案选择得 当,设计的电路可以简单,反之,选得不好,则设计的电路就会复杂许多。在实际设计时,须综合考虑电路复杂度与电路性能之间的折衷。在触发器资源丰富的 FPGA 或 ASIC 设计中,采用独热编码 (one-hot-coding)既可以使电路性能得到保证又可充分利用其触发器数量多的优势,也可以采取输出编码的状态指定来简化电路结构,并提高状态机的运行速度。

(4)选定触发器的类型并求出状态方程、驱动方程和输出方程。

(5)按照方程得出逻辑图:用 Verilog HDL 来描述有限状态机,可以充分发挥硬件描述语言的抽象建模能力,使用always块语句和case(if)等条件语句及赋值语句即可方便实现。具体的逻辑化简、逻辑电路到触发器映射均可由计算机自动完成。上述设计步骤中的第(2)步及(4)、(5)步不再需要很多的人为干预,使电路设计工作得到简化,效率也有很大的提高。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值