当前位置:文档之家› 怎样写好三段式状态机

怎样写好三段式状态机

怎样写好三段式状态机
怎样写好三段式状态机

第6章 如何写好状态机

节选自《Verilog设计与验证》作者:吴继华、王诚

状态机是逻辑设计的重要内容,状态机的设计水平直接反应工程师的逻辑功底,所以许多公司的硬件和逻辑工程师面试中,状态机设计几乎是必选题目。本章在引入状态机设计思想的基础上,重点讨论如何写好状态机。

本章主要内容如下:

?状态机的基本概念;

?如何写好状态机;

?使用Synplify Pro分析FSM。

6.1 状态机的基本概念

本节的重点在于帮助读者理解状态机的基本概念和应用场合。

6.1.1 状态机是一种思想方法

相信大多数工科学生在学习数字电路时都学习过状态机的基本概念,了解一些使用状态机描述时序电路的基本方法。但是,笔者希望大家能扩展思维,认识到状态机不仅仅是一种时序电路设计工具,它更是一种思想方法。

我们先看下面一个简单的例子。在大学生活中,某学生的在校的学习生活可以简单地概括为宿舍、教室、食堂之间的周而复始,用图6-1就可以形象地表现出来。这里画这张图,并不是要讨论这个学生是否是一个“乖乖”类型学生,请大家注意,如果将图中的“地点”认为是“状态”,将“功能”认为是状态的“输出”,这张图就是一张标准的状态转移图,也就是说,我们用状态机的方式清晰地描述了这个学生的在校生活方式。

第6章如何写好状态机

138

状态机的基本概念 139 就是状态机所要描述的核心和强项,换言之,所有具有逻辑顺序和时序规律的事情都适合用状态机描述。

很多初学者不知道何时应用状态机。这里介绍两种应用思路:第一种思路,从状态变量入手。如果一个电路具有时序规律或者逻辑顺序,我们就可以自然而然地规划出状态,从这些状态入手,分析每个状态的输入,状态转移和输出,从而完成电路功能;第二种思路是首先明确电路的输出的关系,这些输出相当于状态的输出,回溯规划每个状态,和状态转移条件与状态输入。无论那种思路,使用状态机的目的都是要控制某部分电路,完成某种具有逻辑顺序或时序规律的电路设计。

其实对于逻辑电路而言,小到一个简单的时序逻辑,大到复杂的微处理器,都适合用状态机方法进行描述。请读者打开思路,不要仅仅局限于时序逻辑,发现电路的内在规律,确认电路的“状态变量”,大胆使用状态机描述电路模型。由于状态机不仅仅是一种电路描述工具,它更是一种思想方法,而且状态机的HDL 语言表达方式比较规范,有章可循,所以很多有经验的设计者习惯用状态机思想进行逻辑设计,对各种复杂设计都套用状态机的设计理念,从而提高设计的效率和稳定性。

6.1.2 状态机基本要素与分类

状态机的基本要素有3个,其实我们在第一节的举例中都有涉及,只是没有点明,它们是:状态、输出和输入。

? 状态:也叫状态变量。在逻辑设计中,使用状态划分逻辑顺序和时序规律。

比如:设计伪随机码发生器时,可以用移位寄存器序列作为状态;在设计电机

控制电路时,可以以电机的不同转速作为状态;在设计通信系统时,可以用信

令的状态作为状态变量等。

? 输出:输出指在某一个状态时特定发生的事件。如设计电机控制电路中,如

果电机转速过高,则输出为转速过高报警,也可以伴随减速指令或降温措施

等。

? 输入:指状态机中进入每个状态的条件,有的状态机没有输入条件,其中的

状态转移较为简单,有的状态机有输入条件,当某个输入条件存在时才能转移

到相应的状态。

根据状态机的输出是否与输入条件相关,可将状态机分为两大类:摩尔(Moore )型状态机和米勒(Mealy )型状态机。

? 摩尔状态机:摩尔状态机的输出仅仅依赖于当前状态,而与输入条件无关。

例如图6-1所示的例子,将图中的“地点”认为是“状态”,将“功能”认为

是状态的“输出”,则每个输出仅仅与状态相关,所以它是一个摩尔型状态

机。

? 米勒型状态机:米勒型状态机的输出不仅依赖于当前状态,而且取决于该状

态的输入条件。例如图6-2所示的例子,将图中的“地点”认为是“状态”,

将“功能”认为是状态的“输出”,将“条件”认为是状态转移的“输入条

件”,大家可以发现,该学生到达什么地方,做什么事情都是由当前状态和输

第6章如何写好状态机

140

入条件共同决定,所以它是一个米勒型状态机。

根据状态机的数量是否为有限个,可将状态机分为有限状态机(Finite State Machine,

FSM)和无限状态机(Infinite State Machine,ISM)。逻辑设计中一般所涉及的状态都是有限的,所以以后我们所说的状态机都指有限状态机,用FSM表示。

6.1.3 状态机的基本描述方式

逻辑设计中,状态机的基本描述方式有3种,分别是:状态转移图,状态转移列表,HDL语言描述。

?状态转移图

状态转移图是状态机描述的最自然的方式。如本章第一节图6-1,6-2都使用了状态转移图这一描述方式。状态转移图经常在设计规划阶段定义逻辑功能

时使用,也可以在分析代码中状态机时使用,通过图形化的方式非常有助于理

解设计意图。

另外值得一提的是目前有一些EDA工具支持状态转移图作为逻辑设计的输入,例如在StateCAD。在该工具中设计者只要画出状态转移图就可以了,

StateCAD能自动将状态转移图翻译成HDL语言代码,而且翻译出来的代码规

范、可读性较好、可综合、易维护。StateCAD还能能自动检测状态机的完备

性和正确性,对状态转移图中的冗余状态、自锁状态、歧义转移条件和不完备

状态机等隐含错误都会报警,并协助设计者更正错误。最后StateCAD会自动

生成设计的测试激励,并调用仿真程序,验证状态机的正确性,这个测试激励

甚至可在后仿真中使用。总之,StateCAD提供了状态机的输入、翻译、检

测、优化和测试等一条龙的服务,使状态机的设计变得安全、可靠、快速、便

捷。这类自动转换状态转移图为HDL源代码的工具对设计、分析一些规模较

小的状态机非常有效,但是由于自动反应的代码过于程式化,效率不是最高,

所以对于较大规模的逻辑设计,一般还是推荐使用HDL语言之间描述。

使用Synplify Pro的RTL视图配合FSM Viewer可以将源代码中描述的FSM用状态转移图

显示出来,使用图形化的界面帮助用户分析理解状态机。关于使用FSM Viewer分析状态机

的方法在本章6.3节有详细介绍。

?状态转移列表

状态转移列表是用列表的方式描述状态机,是数字逻辑电路常用的设计方

法之一,经常被用于对状态化简,对于可编程逻辑设计,由于可用逻辑资源比

较丰富,而且状态编码要考虑设计的稳定性,安全性等因素,所以并不经常使

用状态转移列表优化状态。

?HDL语言描述状态机

使用HDL语言描述状态机是本章讨论的重点,使用HDL语言描述状态机

如何写好状态机

141 有一定的灵活性,但是决不是天马行空,而是有章可循的。通过一些规范的描

述方法,可以使HDL 语言描述的状态机更安全、稳定、高效、易于维护。

6.2 如何写好状态机

本节重点讨论可综合的状态机描述的一些基本规范,即如何在RTL 级描述安全、高效的FSM 。

6.2.1 什么是RTL 级好的FSM 描述

首先介绍好的RTL 级FSM 的评判标准。其实评判FSM 的标准很多,这里我们拣选最重要的几个方面讨论一下。好的RTL 级FSM 的评判标准如下:

? FSM 要安全,稳定性高。

所谓FSM 安全是指FSM 不会进入死循环,特别是不会进入非预知的状态,而

且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。这

里面有两层含义,第一:要求该FSM 的综合实现结果无毛刺等异常扰动;第

二:要求状态机要完备,即使收到异常扰动进入非设计状态,也能很快恢复到

正常状态。

? FSM 速度快,满足设计的频率要求。

任何RTL 设计都应该满足设计的频率要求。

?

FSM 面积小,满足设计的面积要求。

同理任何RTL 设计都应该满足设计的面积要求。 ? FSM 设计要清晰易懂、易维护。

不规范的FSM 写法很难让其他人解读,甚至过一段时间后设计者也发现很难

维护。

需要说明的是以上所列的各项标准,特别是前3项标准绝不是割裂的,它们直接有紧密的内在联系。如果读者读过本工作室的其他书籍,应该记得其中花了相当长的篇幅论述FPGA/CPLD 设计评判的两个基本标准:面积和速度。这里“面积”是指一个设计所消耗FPGA/CPLD 的逻辑资源数量;“速度”指设计在芯片上稳定运行所能够达到的最高频率。两者是对立统一的矛盾体,要求一个设计同时具备设计面积最小,运行频率最高,这是不现实的。科学的设计目标应该是:在满足设计时序要求(包含对设计最高频率的要求)的前提下,占用最小的芯片面积,或者在所规定的面积下,使设计的时序余量更大,频率更高。

另外,如果要求FSM 安全,则很多时候需要使用“full case ”的编码方式,即将状态转移变量的所有向量组合情况都在FSM 中有相应的处理,这经常势必意味着要多花更多的设计资源,有时也会影响FSM 的频率。

所以,各条标准要综合考虑,根据设计的要求进行权衡。但是如果各条评判标准发生冲突时,请按照标准的罗列顺序考虑,前文标准的罗列顺序是根据这些标准在设计中的重要性排列的,也就是说第一条“FSM 要安全,稳定性高”的优先级最高,最重要;第四条

第6章 如何写好状态机

142 “FSM 设计要清晰易懂、易维护”的优先级最低,是相对次要的标准。

6.2.2 RTL 级状态机描述常用语法

本书第2、3章论述了Verilog 的基本语法和常用关键字,其中在RTL 级设计可综合的FSM 相关的常用关键字如下:

? wire 、reg 等

对wire 、reg 等变量、向量定义不加累述,需要补充的是状态编码时(也就是用某种编码描述各个状态)一般都要使用reg 寄存器型向量。

? parameter

用于描述状态名称,增强源代码可读性,简化描述。

例:某状态机使用初始值为“0”的独热码(one-hot )编码方式定义的4bit 宽

度的状态变量NS (代表Next State ,下一状态)和CS (代表Current State ,当前状态),且状态机包含5个具体状态IDLE (空闲状态)、S1(工作状态1)、S2(工作状态2)、S3(工作状态3)、ERROR (告警状态),则代码如下:

reg [3:0] NS,CS;

parameter [3:0] //one hot with zero initial

IDLE = 3’b0000,

S1 = 3’b0001,

S2 = 3’b0010,

S3 = 3’b0100,

ERROR = 3’b1000;

? always

在FSM 设计中有3种always 的使用方法,第1种用法是根据主时钟沿,

完成同步时序的状态迁移。

例:某状态机从当前状态CS 迁移到下一个状态NS 可以如下表述:

//sequential state transition

always @ (posedge clk or negedge nrst)

if (!nrst)

CS <= IDLE;

else

CS <=NS;

always 的第2种用法是根据信号敏感表,完成组合逻辑的输出。

always 的第3种用法是根据时钟沿,完成同步时序逻辑的输出。

? case/endcase

case/endcase 是FSM 描述中最重要的语法关键字,这里我们要详细讨论一

下。case/endcase 的基本语法结构如下:

case (case_expression)

如何写好状态机

143 case_item1 : case_item_statement1;

case_item2 : case_item_statement2;

case_item3 : case_item_statement3;

case_item4 : case_item_statement4;

default : case_item_statement5;

endcase 其中,case_expression 就是case 的判断条件表达式,在FSM 描述中,它

一般为当前状态寄存器;每个case_item 是case 语句的分支列表,在FSM 描述

中,它一般为FSM 中的所有状态的罗列,从中还可以分析出状态的编码方

式;case_item_statement 为进入每个case_item 的对应操作,在FSM 中,即为

每个状态对应的状态转移或者输出,如果case_item_statement 包含的操作不只

一条,可以用begin/end 嵌套多条操作;default 是个可选的关键字,用以指明

当所列的所有case_item 与case_expression 都不匹配时的操作,在FSM 设计

中,为了提高设计的安全性,排除所设计的FSM 进入死循环,一般要求加上

default 关键字来描述FSM 所需状态的补集状态下的操作。另外Verilog 还支

持casex 和casez 等不同关键字,但是由于综合器对这两个关键字的支持情况

略有差异,所以笔者建议初学者使用完整的case 结构而不使用casex 或

casez 。

例:某FSM 的状态转移用case/endcase 结构描述如下:

case (CS)

IDLE: begin

IDLE_out;

if (~i1) NS = IDLE;

if (i1 && i2) NS = S1;

if (i1 && ~i2) NS = ERROR;

end

S1: begin

S1_out;

if (~i2) NS = S1;

if (i2 && i1) NS = S2;

if (i2 && (~i1)) NS = ERROR;

end

S2: begin

S2_out;

if (i2) NS = S2;

if (~i2 && i1) NS = IDLE;

if (~i2 && (~i1)) NS = ERROR;

end

ERROR: begin

第6章 如何写好状态机

144 ERROR_out;

if (i1) NS = ERROR;

if (~i1) NS = IDLE;

end

default: begin

Default_out;

NS = ERROR;

end

endcase

Verilog 的case 结构虽然与C 等高级语言的case 结构虽然形式相似,但是本质不同。

Verilog 的case 结构对应并行判断的硬件结构,而且当case_expression 与任意一个

case_item 匹配后,将忽略对其它case_item 的判断,执行完匹配的case_item_statement 后直

接跳出case 结构。

? task/endtask

task/endtask 在描述状态机是主要用途是将不同状态对应的输出用

task/endtask 封装,增强了代码的可维护性和可读性。

例:某状态机的IDLE 状态的输出可以用task/endtask 封装为“IDEL_out ”

任务:

task IDLE_out;

begin

{w_o1,w_o2,w_err} = 3'b000;

end

endtask 当然描述状态机时也会使用到其它一些常用的RTL 级语法,如if/else ,assign 等等,它们的功能和一般RTL 描述方法一致,这里不在叙述。

6.2.3 推荐的状态机描述方法

状态机描述时关键是要描述清楚前面提到的几个状态机的要素,即如何进行状态转移;每个状态的输出是什么;状态转移是否和输入条件相关等。具体描述时方法各种各样,有的设计者习惯将整个状态机写到1个always 模块里面,在该模块中即描述状态转移,又描述状态的输入和输出,这种写法一般被称为一段式

FSM 描述方法;还有一种写法是将用2个always 模块,其中一个always 模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律,这种写法被称为两段式FSM 描述方法;还有一种写法是在两段式描述方法基础上发展出来的,这种写法使用3个always 模块,一个always 模块采用同步时序描述状态转移;第二个采用组合逻辑判断状态转移条件,描述状态转移规律;第三个always 模块使用同步时序电路描述每个状态的输出,这种写法本书称为三段式写法。

如何写好状态机

145 一般而言,推荐的FSM 描述方法是后两种,即两段式和三段式FSM 描述方法。其原因为:FSM 和其他设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺。状态机实现后,一般来说,状态转移部分是同步时序电路而状态的转移条件的判断是组合逻辑。两段式之所以比一段式编码合理,就在于两段式编码将同步时序和组合逻辑分别放到不同的always 程序块中实现。这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。而一段式FSM 描述不利于时序约束、功能更改、调试等,而且不能很好的表示米勒FSM 的输出,容易写出Latches ,导致逻辑功能错误。

在一般两段式描述中,为了便于描述当前状态的输出,很多设计者习惯将当前状态的输出用组合逻辑实现。但是这种组合逻辑仍然有产生毛刺的可能性,而且不利于约束,不利于综合器和布局布线器实现高性能的设计。因此如果设计运行额外的一个时钟节拍的插入(latency ),则要求尽量对状态机的输出用寄存器寄存一拍。但是很多实际情况不允许插入一个寄存节拍,此时则可以通过三段式描述方法进行解决。三段式与两段式相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出。

为了便于理解,我们通过一个实例讨论这三种不同的写法。

【例1-1】 使用不同的FSM 描述风格描述状态机,参考示例详见本书附带光盘的

“Example-6-1”目录。

在这个范例中我们将用一段式、两段式、三段式分别描述图6-3所示的状态机。这里我们选用了一个非常典型的米勒型状态机,共有4个状态:IDEL, S1, S2, ERROR ;输入信号为时钟clk ,低电平异步复位信号nrst ,输入信号i1,i2,输出信号为o1,o2和err ,状态关系如图6-2所示。状态的输出如下:

IDLE 状态的输出为: {o1,o2,err} = 3'b000;

S1 状态的输出为: {o1,o2,err} = 3'b100;

S2 状态的输出为: {o1,o2,err} = 3'b010;

ERROR 状态的输出为: {o1,o2,err} = 3'b111。

第6章 如何写好状态机

146

图6-3 例子的状态转移图

6.2.3.1 一段式状态机描述方法(应该避免的写法)

该例的一段式描述代码如下:

//1-paragraph method to describe FSM

//Describe state transition, state output, input condition in 1 always block module state1 ( nrst,clk,

i1,i2,

o1,o2,

err

);

input nrst,clk;

input i1,i2;

output o1,o2,err;

reg o1,o2,err;

reg [2:0] NS; //NextState

parameter [2:0] //one hot with zero idle

IDLE = 3'b000,

S1 = 3’b001,

S2 = 3’b010,

ERROR = 3’b100;

//1 always block to describe state transition, state output, input condition

如何写好状态机

147 always @ (posedge clk or negedge nrst)

if (!nrst)

begin

NS <= IDLE;

{o1,o2,err} <= 3'b000;

end

else

begin

NS <= 3'bx;

{o1,o2,err} <= 3'b000;

case (NS)

IDLE: begin if (~i1) begin{o1,o2,err}<=3'b000;NS <= IDLE; end if (i1 && i2) begin{o1,o2,err}<=3'b100;NS <= S1; end

if (i1 && ~i2) begin{o1,o2,err}<=3'b111;NS <= ERROR;end

end

S1: begin

if (~i2) begin{o1,o2,err}<=3'b100;NS <= S1; end if (i2 && i1) begin{o1,o2,err}<=3'b010;NS <= S2; end

if (i2 && (~i1)) begin{o1,o2,err}<=3'b111;NS <= ERROR;end

end

S2: begin

if (i2) begin{o1,o2,err}<=3'b010;NS <= S2; end

if (~i2 && i1) begin{o1,o2,err}<=3'b000;NS <= IDLE; end

if (~i2 && (~i1))begin{o1,o2,err}<=3'b111;NS <= ERROR;end

end

ERROR: begin

if (i1) begin{o1,o2,err}<=3'b111;NS <= ERROR;end if (~i1) begin{o1,o2,err}<=3'b000;NS <= IDLE; end end

endcase

end

endmodule

如前面介绍,一段式写法就是将状态的同步转移,状态输出和状态的输入条件都写在一个always 模块中,一段式写法可以概括为图6-4描述的结构。

第6章 如何写好状态机

148

图6-4 一段式FSM 描述结构图

一段式描述方法将状态转移判断的组合逻辑和状态寄存器转移的时序逻辑混写在同一个always 模块中,不符合将时序和组合逻辑分开描述的Coding Style (代码风格),而且在描述当前状态时要考虑下个状态的输出,整个代码不清晰,不利于维护修改,并且不利于附加约束,不利于综合器和布局布线器对设计的优化。

另外,这种描述相对于两段式描述比较冗长。本例为了便于初学者掌握,选择了一个非常简单的米勒型状态机,不能很好的反应一段式比较冗长的缺点,但是如果状态机相对复杂些,一般来说,一段式代码长度会比两段式冗长大约80%到150%左右。

所以一段式FSM 描述是不推荐的FSM 描述方式,请读者一定要避免。

6.2.3.2 两段式状态机描述方法(推荐写法)

为了使FSM 描述清晰简介,易于维护,易于附加时序约束,使综合器和布局布线器更好的优化设计,推荐使用两段式FSM 描述方法。

本例的两段式描述代码如下:

//2-paragraph method to describe FSM

//Describe sequential state transition in 1 sequential always block

//State transition conditions in the other combinational always block

//Package state output by task. Then register the output

module state2 ( nrst,clk,

i1,i2,

o1,o2,

err );

如何写好状态机

149 input nrst,clk;

input i1,i2;

output o1,o2,err;

reg o1,o2,err;

reg [2:0] NS,CS;

parameter [2:0] //one hot with zero idle

IDLE = 3'b000,

S1 = 3’b001,

S2 = 3’b010,

ERROR = 3’b100;

//sequential state transition

always @ (posedge clk or negedge nrst)

if (!nrst)

CS <= IDLE;

else

CS <=NS;

//combinational condition judgment

always @ (CS or i1 or i2)

begin

NS = 3'bx;

ERROR_out;

case (CS)

IDLE: begin

IDLE_out;

if (~i1) NS = IDLE;

if (i1 && i2) NS = S1;

if (i1 && ~i2) NS = ERROR;

end

S1: begin

S1_out;

if (~i2) NS = S1;

if (i2 && i1) NS = S2;

if (i2 && (~i1)) NS = ERROR;

end

S2: begin

S2_out;

if (i2) NS = S2;

if (~i2 && i1) NS = IDLE;

if (~i2 && (~i1)) NS = ERROR;

第6章如何写好状态机

150

end

ERROR: begin

ERROR_out;

if (i1) NS = ERROR;

if (~i1) NS = IDLE;

end

endcase

end

//output task

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

两段式写法是推荐的FSM描述方法之一,在此我们仔细讨论一下代码结构。两段式

FSM的核心就是:一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律。两段式写法可以概括为图6-5描述的结构。

如何写好状态机

151

图6-5 两段式FSM 描述结构图

本例中,同步时序描述状态转移的always 模块代码如下:

always @ (posedge clk or negedge nrst)

if (!nrst)

CS <= IDLE;

else

CS <=NS;

其实这是一种程式化的描述结构,无论具体到何种FSM 设计,都可以定义两个状态寄存器“CS ”和“NS ”,分别代表当前状态和下一状态,然后根据所需的复位方式(同步复位或异步复位),在时钟沿到达时将NS 赋给CS 。需要注意的是这个同步时序模块的赋值要采用非阻塞赋值“<=”。

本例中,另一个采用组合逻辑判断状态转移条件的always 模块代码如下:

//combinational condition judgment

always @ (nrst or CS or i1 or i2)

begin

NS = 3'bx;

ERROR_out;

case (CS)

IDLE: begin

IDLE_out;

if (~i1) NS = IDLE;

if (i1 && i2) NS = S1;

第6章如何写好状态机

152

if (i1 && ~i2) NS = ERROR;

end

S1: begin

S1_out;

if (~i2) NS = S1;

if (i2 && i1) NS = S2;

if (i2 && (~i1)) NS = ERROR;

end

S2: begin

S2_out;

if (i2) NS = S2;

if (~i2 && i1) NS = IDLE;

if (~i2 && (~i1)) NS = ERROR;

end

ERROR: begin

ERROR_out;

if (i1) NS = ERROR;

if (~i1) NS = IDLE;

end

endcase

end

这个使用组合逻辑判断状态转移条件的always模块也可以看成格式化的书写结构。其

中always的敏感列表为当前状态“CS”,复位信号和输入条件(如果是米勒状态机,则必须有输入条件;如果是摩尔状态机,一般敏感表和后续逻辑判定没有输入),请大家注意电平敏感表必须列完整。本例中这段电平敏感列表为:

always @ (nrst or CS or i1 or i2)

一般来说,在这个组合always敏感表下先写一个默认的下一状态“NS”的描述,然后根据实际的状态转移条件由内部的case或者if...else条件判断确定正确的转移。如本例中下面这段代码,

……

begin

NS = ERROR;

ERROR_out;

case (CS)

……

推荐在敏感表下的默认状态为不定状态X,这样描述的好处有两个:第一在仿真时可以很好的考察所设计的FSM的完备性,如果所设计的FSM不完备,则会进入任意状态,仿真很容易发现;第二个好处是综合器对不定态X的处理是“Don’t Care”,即任何没有定义的状态寄存器向量都会被忽略。这里赋值不定态的效果和使用casez或casex替代case的效果

如何写好状态机 153 非常相似。

在每个case 模块的内部的结构也非常相似,都是先描述当前状态的组合逻辑输出,然后根据输入条件(米勒FSM )判定下一个状态。

该组合逻辑模块中所有的赋值推荐采用阻塞赋值“=”。

对于每个输出,一般用组合逻辑描述,比较简便的方法是用task/endtask 将输出封装起来,这样做的好处不仅仅是写法简单,而且利于复用共同的输出。例如本例中S1状态的输出被封装为S1_out ,在组合逻辑always 模块中直接调用即可。

task S1_out;

{o1,o2,err} = 3'b100;

endtask

组合逻辑容易产生毛刺,因此如果时序允许,请尽量对组合逻辑的输出插入一个寄存器节拍,这样可以很好的保证输出信号的稳定性。

6.2.3.3 三段式状态机描述方法(推荐写法)

两段式FSM 描述方法虽然有很多好处,但是它有一个明显的弱点就是其输出一般使用组合逻辑描述,而组合逻辑易产生毛刺等不稳定因素,并且在FPGA/CPLD 等逻辑器件中过多的组合逻辑会影响实现的速率(这点与ASIC 设计不同)。所以在上节我们特别提到了在两段式FSM 描述方法中,如果时序允许插入一个额外的时钟节拍,则尽量在在后级电路对FSM 的组合逻辑输出用寄存器寄存一个节拍,则可以有效地消除毛刺。但是很多情况下,设计并不允许额外的节拍插入(Latency ),此时,解决之道就是采用3段式FSM 描述方法。三段式描述方法与两段式描述方法相比,关键在于使用同步时序逻辑寄存FSM 的输出。

本例的三段式描述代码如下:

//3-paragraph method to describe FSM

//Describe sequential state transition in the 1st sequential always block //State transition conditions in the 2nd combinational always block

//Describe the FSM out in the 3rd sequential always block

module state2 ( nrst,clk,

i1,i2,

o1,o2,

err

);

input nrst,clk;

input i1,i2;

output o1,o2,err;

第6章如何写好状态机

154 reg o1,o2,err;

reg [2:0] NS,CS;

parameter [2:0] //one hot with zero idle

IDLE = 3'b000,

S1 = 3'b001,

S2 = 3'b010,

ERROR = 3'b100;

//1st always block, sequential state transition

always @ (posedge clk or negedge nrst)

if (!nrst)

CS <= IDLE;

else

CS <=NS;

//2nd always block, combinational condition judgment

always @ (nrst or CS or i1 or i2)

begin

NS = 3'bx;

case (CS)

IDLE: begin

if (~i1) NS = IDLE; if (i1 && i2) NS = S1;

if (i1 && ~i2) NS = ERROR; end

S1: begin

if (~i2) NS = S1;

if (i2 && i1) NS = S2;

if (i2 && (~i1)) NS = ERROR; end

S2: begin

if (i2) NS = S2;

if (~i2 && i1) NS = IDLE; if (~i2 && (~i1)) NS = ERROR; end

ERROR: begin

if (i1) NS = ERROR; if (~i1) NS = IDLE;

end

endcase

end

如何写好状态机

155 //3rd always block, the sequential FSM output

always @ (posedge clk or negedge nrst)

if (!nrst)

{o1,o2,err} <= 3'b000;

else

begin

{o1,o2,err} <= 3'b000;

case (NS)

IDLE: {o1,o2,err}<=3'b000;

S1: {o1,o2,err}<=3'b100;

S2: {o1,o2,err}<=3'b010;

ERROR: {o1,o2,err}<=3'b111;

endcase

end

endmodule 三段式写法可以概括为图6-6描述的结构。

图6-6 三段式FSM 描述结构图

对比一下上节两段式FSM 的描述,读者可以清晰发现三段式与两段式FSM 描述的最大区别在于两段式采用了组合逻辑输出,而三段式巧妙地根据下一状态的判断,用同步时序逻辑寄存FSM 的输出。本例中就是下面一段代码,

always @ (posedge clk or negedge nrst)

if (!nrst) {o1,o2,err} <= 3'b000;

第6章如何写好状态机

156

else

begin

{o1,o2,err} <= 3'b000;

case (NS)

IDLE: {o1,o2,err}<=3'b000;

S1: {o1,o2,err}<=3'b100;

S2: {o1,o2,err}<=3'b010;

ERROR: {o1,o2,err}<=3'b111;

endcase

end

有的读者可能会问,一段式写法也是用寄存器同步了FSM的输出,为什么前面介绍一

段式的输出代码容易混淆,不利于维护呢?请大家对比一下 6.2.3.1小节的这段一段式输出的代码,

……

case (NS)

IDLE: begin

if (~i1) begin{o1,o2,err}<=3'b000;NS <= IDLE; end

if (i1 && i2) begin{o1,o2,err}<=3'b100;NS <= S1; end

if (i1 && ~i2) begin{o1,o2,err}<=3'b111;NS <= ERROR;end end

……

通过对比,可以清晰地看到:使用一段式建模FSM的寄存器输出的时候,必须要综合考虑现态在何种状态转移条件下会进入哪些次态,然后在每个现态的case分支下分别描述每个次态的输出,这显然不符合思维习惯;而三段式建模描述FSM的状态机输出时,只需指定case敏感表为次态寄存器,然后直接在每个次态的case分支中描述该状态的输出即可,根本不用考虑状态转移条件。本例的FSM很简单,如果设计的FSM相对复杂,三段式的描述优势就会凸显出来。

另一方面,三段式描述方法与两段式描述相比,虽然代码结构复杂了一些,但是换来的优势是使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。

6.2.3.4 三种描述方法与状态机建模问题的引申

可以说合理的状态机描述与状态机的建模技巧是本章的重中之重。这里需要引申讨论几个问题。

verilog经典三段式状态机设计实例

Moore型verilog源代码:FSM实现10010串的检测Moore状态转移图 module moorefsm(clk,rst,a,z); input clk,rst; input a; output z; reg z; reg [3:0] currentstate,nextstate; parameter S0 = 4'b0000; parameter S1 = 4'b0001; parameter S2 = 4'b0010; parameter S3 = 4'b0011; parameter S4 = 4'b0100; parameter S5 = 4'b0101; always@(posedge clk or negedge rst) begin if(!rst) currentstate <= S0; else

currentstate <= nextstate; end always@(currentstate or a or rst) begin if(!rst) nextstate = S0; else case(currentstate) S0: nextstate = (a==1)?S1:S0; S1: nextstate = (a==0)?S2:S1; S2: nextstate = (a==0)?S3:S1; S3: nextstate = (a==1)?S4:S0; S4: nextstate = (a==0)?S5:S1; S5: nextstate = (a==0)?S3:S1; default: nextstate = S0; endcase end always@(rst or currentstate) begin if(!rst) z = 0; else case(currentstate) S0: z = 0;S1: z = 0;S2: z = 0; S3: z = 0;S4: z = 0;S5: z = 1; default: z = 0; endcase end endmodule

帧格式头数据检测_VerilogHDL有限状态机

题目1:串行通讯中,经常要检测数据包的开始标志,例如:USB 数据包的起 始数据是8‘b00101010设计一个电路,能够检测串行数据流中的特殊数据串,并在数据串有效时,给出相应的指示信号; (1)RTL Code /*信号定义与说明 Clk:同步时钟 rstb: 异步复位信号,低电平复位 up_down: 加/减计数方向控制信号,1为加计数 Din:串行数据输入 pat_det: 检测结果输出 */ `timescale 1ns/1ns module serialdata(din,clk,rstb,pat_det); input clk,rstb; input din; output pat_det; parameter S0='d0,S1='d1,S2='d2,S3='d3,S4='d4,S5='d5,S6='d6,IDLE='d7; reg[2:0] state; assign pat_det=(state= =S6&&din= =0)?1:0; always@(posedge clk or negedge rstb) begin if(!rstb) state<=IDLE; else begin case(state) IDLE: begin if(din==0) state<=S0; else state<=IDLE; end S0: begin if(din==0) state<=S1; else state<=IDLE; end S1: begin if(din==1) state<=S2; else state<=S1; end S2:

begin if(din==0) state<=S3; else state<=IDLE; end S3: begin if(din==1) state<=S4; else state<=S1; end S4: begin if(din==0) state<=S5; else state<=IDLE; end S5: begin if(din==1) state<=S6; else state<=S1; end S6: state<=IDLE; default: state<=IDLE; endcase end end endmodule (2)Test File `timescale 1ns/1ns `include "serialdata.v" module tb_serialdata; reg clk,rstb; wire din; wire pat_det; reg[31:0] data; assign din=data[31]; serialdata t1(din,clk,rstb,pat_det); initial begin clk=1'b0; rstb=1'b0; data=32'b1001_0010_1010_1100_1010_1000_1010_1010; #10 rstb=1'b1; #640 $stop; end

verilog可综合有限状态机的4种写法(夏文宇书注)

verilog可综合有限状态机的4种写法(夏文宇书注) 第一种:自然编码 module fsm1( input i_clk, input rst_n, input A, output reg K1, output reg K2, output reg [1:0] state ); parameter Idle=2'b00, Start=2'b01, Stop=2'b10, Clear=2'b11; [email=always@(posedge]always@(posedge[/email] i_clk) if(!rst_n) 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) state<=Stop; else state<=Start; Stop:if(A) begin state<=Clear; K2<=1;

else begin state<=Stop; K2<=0; K1<=0; end Clear:if(!A) begin state<=Idle; K1<=1; K2<=0; end else begin state<=Clear; K2<=0; K1<=1; end default: state<=Idle; endcase endmodule 这种大家应该都熟悉的 第二种:采用独热编码,据说其可靠性和速度都不错module fsm2( input i_clk, input rst_n, input A, output reg K1, output reg K2, output reg [3:0] state ); parameter Idle=4'b1000; parameter Start=4'b0100; parameter Stop=4'b0010; parameter Clear=4'b0001; always@(posedge i_clk) begin if(!rst_n)

Verilog三段式状态机的建模方法和注意事项

Verilog三段式状态机(FSM) 网上收集整理…… 时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息。 状态机采用VerilogHDL语言编码,建议分为三个always段完成。这是为什么呢? 设计FSM的方法和技巧多种多样,但是总结起来有两大类:第一种,将状态转移和状态的操作和判断等写到一个模块(process、block)中。另一种是将状态转移单独写成一个模块,将状态的操作和判断等写到另一个模块中(在Verilog代码中,相当于使用两个“always”block)。其中较好的方式是后者。其原因如下。 首先FSM和其他设计一样,最好使用同步时序方式设计,好处不再累述。而状态机实现后,状态转移是用寄存器实现的,是同步时序部分。状态的转移条件的判断是通过组合逻辑判断实现的,之所以第二种比第一种编码方式合理,就在于第二种编码将同步时序和组合逻辑分别放到不同的程序块(process,block)中实现。这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。 三段式建模描述FSM的状态机输出时,只需指定case敏感表为次态寄存器,然后直接在每个次态的case分支中描述该状态的输出即可,不用考虑状态转移条件。 三段式描述方法虽然代码结构复杂了一些,但是换来的优势是使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。 示例如下: //第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器 always @ (posedge clk or negedge rst_n) //异步复位 if(!rst_n) current_state <= IDLE; else current_state <= next_state;//注意,使用的是非阻塞赋值 //第二个进程,组合逻辑always模块,描述状态转移条件判断 always @ (current_state) //电平触发 begin next_state = x; //要初始化,使得系统复位后能进入正确的状态 case(current_state) S1: if(...) next_state = S2; //阻塞赋值 ... endcase end

Verilog代码描述对状态机综合的研究

Verilog HDL代码描述对状态机综合的研究 1 引言 Verilog HDL作为当今国际主流的HDL语言,在芯片的前端设计中有着广泛的应用。它的语法丰富,成功地应用于设计的各个阶段:建模、仿真、验证和综合等。可综合是指综合工具能将Verilog HDL代码转换成标准的门级结构网表,因此代码的描述必须符合一定的规则。大部分数字系统都可以分为控制单元和数据单元两个部分,控制单元的主体是一个状态机,它接收外部信号以及数据单元产生的状态信息,产生控制信号,因而状态机性能的好坏对系统性能有很大的影响。 有许多可综合状态机的Verilog代码描述风格,不同代码描述风格经综合后得到电路的物理实现在速度和面积上有很大差别。优秀的代码描述应当易于修改、易于编写和理解,有助于仿真和调试,并能生成高效的综合结果。 2 有限状态机 有限状态机(Finite State Machine,FSM)在数字系统设计中应用十分广泛。根据状态机的输出是否与输入有关,可将状态机分为两大类:摩尔(Moore)型状态机和米莉(Mealy)型状态机。Moore型状态机的输出仅与现态有关;Mealy型状态机的输出不仅与现态有关,而且和输入也有关。图1是有限状态机的一般结构图,它主要包括三个部分,其中组合逻辑部分包括状态译码器和输出译码器,状态译码器确定状态机的下一个状态,输出译码器确定状态机的输出,状态寄存器属于时序逻辑部分,用来存储状态机的内部状态。 图1 状态机的结构框图 2.1 好的状态机标准 好的状态机的标准很多,最重要的几个方面如下: 第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。这里面有两层含义。其一要求该FSM的综合实现结果无毛刺等异常扰动,其二要求FSM要完备,即使受到异常扰动进入非设计状态,也能很快恢复到正常状态。 第二,状态机的设计要满足设计的面积和速度的要求。 第三,状态机的设计要清晰易懂、易维护。 需要说明的是,以上各项标准,不是割裂的,它们有着直接紧密的内在联系。在芯片设计中,对综合结果评判的两个基本标准为:面积和速度。“面积”是指设计所占用的逻辑资源数量;“速度”指设计在芯片上稳定运行所能够达到的最高频率。两者是对立统一的矛盾体,要求一个设计同时具备设计面积最小,运行频率最高,这是不现实的。科学的设计目标应该是:在满足设计时序要求(包含对设计最高频率的要求)的前提下,占用最小

verilog有限状态机实验报告(附源代码)

有限状态机实验报告 一、实验目的 ●进一步学习时序逻辑电路 ●了解有限状态机的工作原理 ●学会使用“三段式”有限状态机设计电路 ●掌握按键去抖动、信号取边沿等处理技巧 二、实验内容 用三段式有限状态机实现序列检测功能电路 a)按从高位到低位逐位串行输入一个序列,输入用拨动开关实现。 b)每当检测到序列“1101”(不重叠)时,LED指示灯亮,否则灭,例如 i.输入:1 1 0 1 1 0 1 1 0 1 ii.输出:0 0 0 1 0 0 0 0 0 1 c)用八段数码管显示最后输入的四个数,每输入一个数,数码管变化一次 d)按键按下的瞬间将拨动开关状态锁存 i.注意防抖动(按键按下瞬间可能会有多次的电平跳变) 三、实验结果 1.Rst_n为0时数码管显示0000,led灯不亮,rst_n拨为1,可以开始输入,将输 入的开关拨到1,按下按钮,数码管示数变为0001,之后一次类推分别输入1, 0,1,按下按钮后,数码管为1101,LED灯亮,再输入1,LED灯灭,之后再输 入0,1(即共输入1101101使1101重叠,第二次LED灯不亮),之后单独输入

1101,LED灯亮 2.仿真图像 刚启动时使用rst_n 一段时间后 其中Y代表输出,即控制led灯的信号,sel表示数码管的选择信号,seg表示数码管信号 四、实验分析 1、实验基本结构

其中状态机部分使用三段式结构: 2、整体结构为:

建立一下模块: Anti_dither.v 输入按键信号和时钟信号,输出去除抖动的按键信号生成的脉冲信号op 这一模块实现思路是利用按钮按下时会持续10ms以上而上下抖动时接触时间不超过10ms来给向下接触的时间计时,达到上限时间才产生输出。 Num.v 输入op和序列输入信号A,时钟信号clk和复位信号,复位信号将num置零,否则若收到脉冲信号则将num左移一位并将输入存进最后一位。输出的num即为即将在数码管上显示的值 Scan.v 输入时钟信号,对其降频以产生1ms一次的扫描信号。 Trigger.v 这一模块即为状态机模块,按三段式书写。 整个模块的输入为时钟信号,脉冲信号,序列输入变量,复位信号,输出LED灯控制信号Y。 第一段是状态转换模块,为时序逻辑电路,功能是描述次态寄存器迁移到现态寄存器。即如果收到复位信号将现态置零,否则将上次得到的next_state赋给current_state。

Verilog状态机的写法

Verilog状态机的写法-转 1 引言 Verilog HDL作为当今国际主流的HDL语言,在芯片的前端设计中有着广泛的应用。它的语法丰富,成功地应用于设计的各个阶段:建模、仿真、验证和综合等。可综合是指综合工具能将Verilog HDL代码转换成标准的门级结构网表,因此代码的描述必须符合一定的规则。大部分数字系统都可以分为控制单元和数据单元两个部分,控制单元的主体是一个状态机,它接收外部信号以及数据单元产生的状态信息,产生控制信号,因而状态机性能的好坏对系统性能有很大的影响。 有许多可综合状态机的Verilog代码描述风格,不同代码描述风格经综合后得到电路的物理实现在速度和面积上有很大差别。优秀的代码描述应当易于修改、易于编写和理解,有助于仿真和调试,并能生成高效的综合结果。 2 有限状态机 有限状态机(Finite State Machine,FSM)在数字系统设计中应用十分广泛。根据状态机的输出是否与输入有关,可将状态机分为两大类:摩尔(Moore)型状态机和米莉 (Mealy)型状态机。Moore型状态机的输出仅与现态有关;Mealy型状态机的输出不仅与现态有关,而且和输入也有关。图1是有限状态机的一般结构图,它主要包括三个部分,其中组合逻辑部分包括状态译码器和输出译码器,状态译码器确定状态机的下一个状态,输出译码器确定状态机的输出,状态寄存器属于时序逻辑部分,用来存储状态机的内部状态。 图1 状态机的结构框图 2.1 好的状态机标准 好的状态机的标准很多,最重要的几个方面如下: 第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。这里面有两层含义。其一要求该FSM的综合实现结果无毛刺等异常扰动,其

Verilog HDL入门基础之时序状态机的设计

时序状态机的设计入门与提高 计算机及具有存储器或按照所存储信息执行一系列操作的其他数字系统统称为“时序状态机”,其电路可以通过时序逻辑进行建模。时序状态机的性能与组合逻辑不同,因为时序状态机的输出不仅仅取决于当前的输入值,而且取决于历史的输入值。时序状态机被广泛应用于需要指定顺序操作的应用中。所有的时序状态机都具有如图的通用反馈结构,在这种结构中时序状态机的下一状态是由当前状态和当前输入一起形成的: 时序状态机可以按是否受一个公共的时钟控制(钟控)分为同步状态机和异步状态机;根据状态数目是否有限分为有限状态机和无限状态机。此处只讨论有限状态机。 有限状态机的(FSM)分类 有限状态机有米利(Mealy)机和摩尔(Moore)机: 米利(Mealy)机: 米利(Mealy)机的下一状态和输出都取决于当前状态和当前输入。 摩尔(Moore)机: 摩尔(Moore)机的下一状态取决于当前状态和当前输入,而输出仅仅取决于当前状态。 有限状态机常用的描述、开发方法 有限状态机可以借助时序图、状态表、状态图以及ASM图进行系统的描述与设计。

?时序图可以用于说明系统中及系统与周围环境的接口中信号的有效输入与状态转移之间的关系。 ?状态表与状态转移表以表格的形式表示在当前状态和输入的各种组合下状态机的下一状态和输出 ?状态转移图(STG)是一种有向图,图中带有标记的节点或顶点与时序状态机的状态一一对应。当系统处于弧线起点的状态时,用有向边或弧线表示在输入信号的作用下可能发生的状态转移。米利机STG的顶点用状态进行标记,状态转移图的有向边有下面两种标记方法: (1)用能够导致状态向指定的下一状态转移的输入信号来标记 (2)在当前状态下,用输入信号的输出来进行标记 摩尔机的状态转移图与米利机相类似,但它的输出是由各状态的顶点来表示的,而不是在弧线上表示 ?算法状态机(ASM)图是时序状态机功能的一种抽象,是模拟其行为特性的关键工具。 它类似于软件流程图,但显示的是计算流程图(如寄存器操作)的时间顺序,以及在状态机输入影响下发生的时序步骤。ASM图描述的是状态机的行为动作,而不是存储元件所存储的内容。有时候用机器工作期间的行为动作来描述状态机的状态,比起用状态机产生的数据进行描述更为方便也更为重要 ?ASMD图是ASM图的扩展。状态机的一个重要应用就是控制时序状态机数据通道上的寄存器操作,而该时序状态机已被分为控制器和数据通道。控制器可以用ASM图来描述,我们修改ASM图的目的是把它连接到状态机所控制的数据通道上。当控制器的状态沿着通道发生转移时,通过标注每个数据通道来指出那些在相关数据通道单元中所发生的寄存器操作以这种方式连接到数据通道的ASM图被称为算法状态机和数据通道(ASMD)图。在把时序状态机数据通道的设计从控制器的设计中分离出来,并在两个单元之间保持清晰联系的情况下,ASMD图有助于阐明这样的时序状态机设计方法。与状态转移并行发生的寄存器操作是在图的通道上标注的,而不是在通道上的条件框或状态框中标注的,因为这些寄存器并不是控制器的一部分。由控制器产生的输出是那些控制数据通道寄存器的信号,以及引发ASM图上标注的寄存器操作的信号。 基于状态转移图(STG)的设计 对于一个同步时序状态机的给定的STG,设计的任务就是确定下一状态和输出逻辑。如果用一个二进制码来表示时序状态机的状态,那么其值可以存储在触发器中。在时钟的各个有效沿处,状态保持触发器的输入变成下一个时钟周期的状态。同步时序状态机的设计就是要根据机器的状态和外部输入来确定能形成触发器输入的逻辑,该逻辑为组合逻辑,并且应该是最简逻辑。对于有效地STG而言,其每个顶点必须表示一个唯一的状态;每个弧线则表示在指定输入信号的作用下,从给定状态到下一状态的转移,并且从一个节点出发的各弧线必须对应一个唯一的输入。通常,与从一个节点出发的一组弧线有关的布尔条件必须满足和为1(即状态转移图必须考虑到从一个节点出发的所有的可能的状态转移),并且在给定状态下与输入变量判定有关的每个分支条件必须对应于一条唯一的弧线(即时序状态机仅可以由一个节点经过一条弧线转移到下一状态)。根据时钟到来之前的状态值和当前输入值,由同步时序状态机的STG所表示的状态转移将在时钟信号的有效沿处发生。 基于状态转移图(STG)的有限状态机的系统设计方法通常包括以下几个步骤: (1)构建状态机的STG (2)消去等价状态

2014.9摩尔及米利型状态机的VerilogHDL描述方法

例1:MOORE 型状态机 设某个控制器的状态转换图如下所示: 输入:in 、时钟clk 、和复位信号 输出:out 用Verilog 将NS 、 OL 、 CS module statmach(clk, in, reset, out); input clk, reset; //时钟、复位信号 input in; //输入 output out; reg out; //输出 reg current_state; //现态寄存器 reg next_state; //次态寄存器,NS 与CS 分开描述时必须定义 parameter s0 = 0, s1 = 1; //状态编码 always @( current_state or in ) begin case (current_state) s0: if(in) next _state<=s1; else if (!in) next _state<=s0 s1: if(in) next _state<=s0; else if (!in) next _state<=s1default: next _state<=s0; endcase end always @(posedge clk ) begin if (reset) current_state <= s0; else current_state<= next end always @( current_state ) in=0 状态编码:S0=0,S1=1。 in=0 时钟CS NS OL 复位

begin case (current_state) s0: out <= 0; s1: out <= 1; default: out <= x; endcase end endmodule 将CS 与NS 混合描述,OL 单独描述: module statmach(clk, in, reset, out); input clk, reset; //时钟、复位信号 input in; //输入 output out; //输出 reg out; reg current_state; //现态寄存器 parameter s0 = 0, s1 = 1; //状态编码 always @(posedge clk ) begin if (reset) current_state = s0; else case (current_state) s0: if (in) current_state = s1; else if (!in) current_state = s0; s1: if (in) current_state = s0; else if (!in) current_state = s1; default: current_state = s0; endcase end in=0 OL 时钟CS NS OL MOORE 型状态机结构图 复位

AD7656 verilog 状态机

module adc(data,clk,Busy,cs_n,convsta,convstb,convstc,rd,databuf); input [15:0] data;//???? input clk,Busy; output convsta,convstb,convstc;//?????? output rd,cs_n; output [15:0] databuf;//?? reg rd; reg [15:0] REGL; reg convsta,convstb,convstc; wire cs_n; wire [15:0] databuf; parameter st0=4'b0000, st1=4'b0001, st2=4'b0010, st3=4'b0011, st4=4'b0100, st5=4'b0101; parameter st6=4'b0110, st7=4'b0111, st8=4'b1000, st9=4'b1001, st10=4'b1010, st11=4'b1011; parameter st12=4'b1100, st13=4'b1101; reg [3:0] current_states, next_states; assign cs_n= 0; assign databuf= REGL; always@(posedge clk) begin current_states<= next_states; end always@(*) begin

case(current_states) st0:begin// ??? convsta= 0; convstb= 0; convstc=0; next_states=st1; rd=1'b1; end st1:begin//??AD?? convsta= 1; convstb=1; convstc= 1; next_states= st2; rd= 1; end st2:begin//?????? convsta=0; convstb= 0; convstc=0; rd= 1; if(Busy==0) begin next_states= st3; rd=1; end else next_states= st2; end st3: begin //????????? convsta= 0; convstb= 0; convstc=0; rd=0; REGL = data; next_states= st4; end st4: begin //??RD convsta= 0; convstb= 0; convstc=0;

FPGA_ADC0809_statemechine verilog 代码(状态机)

// FPGA接50MHZ 晶振 `timescale 1ns/1ns module ADC0809_statemechine( sys_clk, sys_rstn, adc_clk, adc_start, adc_eoc, adc_oe, adc_ale, adc_data, adc_led, ); input sys_clk,sys_rstn,adc_eoc; input [0:7]adc_data; output adc_clk,adc_start,adc_ale,adc_oe; output [0:7]adc_led; reg adc_clk, adc_start, adc_ale, adc_oe, lock; reg [0:7]adc_led; reg [0:7]counter_500k; reg [0:7]state; parameter idle =8'b00000000, ale_enable =8'b00000001, start_1 =8'b00000010, start_0 =8'b00000100, eoc_0 =8'b00001000, eoc_1 =8'b00010000, oe_enable =8'b00100000, get_data =8'b01000000; initial begin state=8'b00000000; adc_ale=1'b0; adc_start=1'b0; adc_oe=1'b0; adc_clk=1'b0; adc_led<=8'b11111111; end

always @(posedge sys_clk) begin counter_500k<=counter_500k+1'b1; if (counter_500k>=8'd50) begin counter_500k<=8'd0; adc_clk<=~adc_clk; //500khz(2us), ADC work frquency/clock end end always @(posedge adc_clk) begin case (state) idle: begin adc_ale<=1'b0; adc_start<=1'b0; adc_oe<=1'b0; lock<=1'b0; state<=ale_enable; end ale_enable: begin adc_ale<=1'b1; adc_start<=1'b0; adc_oe<=1'b0; lock<=1'b0; state<=start_1; end start_1: begin adc_ale<=1'b0; adc_start<=1'b1; adc_oe<=1'b0; lock<=1'b0; state<=start_0; end start_0: begin adc_ale<=1'b0;

Verilog可综合有限状态机的4种写法

Verilog可综合有限状态机的4种写法 第一种:自然编码 1.module fsm1( 2.input i_clk, 3.input rst_n, 4.input A, 5.output reg K1, 6.output reg K2, 7.output reg [1:0] state 8.);[/color][/font] 9.[font=Times New Roman][color=#000000]parameter Idle=2'b00, 10. Start=2'b01, 11. Stop=2'b10, 12. Clear=2'b11;[/color][/font] 13.[font=Times New Roman][color=#000000][email=always@(posedge]always@(posedge[/email] i_clk) 14.if(!rst_n) 15.begin 16. state<=Idle; 17. K2<=0; 18. K1<=0; 19.end 20.else 21.case(state) 22. Idle:if(A) 23. begin 24. state<=Start; 25. K1<=0; 26. end

28. begin 29. state<=Idle; 30. K2<=0; 31. K1<=0; 32. end 33. Start:if(!A) 34. state<=Stop; 35. else 36. state<=Start; 37. Stop:if(A) 38. begin 39. state<=Clear; 40. K2<=1; 41. end 42. else 43. begin 44. state<=Stop; 45. K2<=0; 46. K1<=0; 47. end 48. Clear:if(!A) 49. begin 50. state<=Idle; 51. K1<=1; 52. K2<=0; 53. end 54. else 55. begin 56. state<=Clear; 57. K2<=0; 58. K1<=1;

FSM状态机verilog代码

#M16 `timescale 1ns/10ps //4-bits counter module m16( output reg [3:0] ctr=0, input clock, input reset); always@(posedge clock) begin if(reset==1) ctr <= 0; else ctr <= ctr + 1; end endmodule #M555 `timescale 1ns/10ps //clock and reset generation module m555( output reg clock, output reg reset); initial begin #5 clock=1;reset=1; #500 reset=0; end always #50 clock=~clock;

endmodule # mealyfsm_testbench `timescale 1ns/10ps //1ns means delay unit and 10ps means delay precision module mealyfsm_testbench; wire clock; wire reset; wire xin; wire [1:0] yout; mealyfsm_testgen inst_mealyfsm_testgen( .clock(clock), .reset(reset), .xin(xin), .yout(yout) ); mealyfsm inst_mealyfsm( .clk(clock), .reset(reset), .xin(xin), .yout(yout) ); endmodule # mealyfsm_testgen `timescale 1ns/10ps //1ns means delay unit and 10ps means delay precision module mealyfsm_testgen( output clock,

Verilog中三段式状态机模板

在用Verilog编写状态机时,建议分为三个always段完成。 三段式建模描述FSM的状态机输出时,只需指定case敏感表为次态寄存器,然后直接在每个次态的case分支中描述该状态的输出即可,不用考虑状态转移条件。 三段式描述方法虽然代码结构复杂了一些,但是换来的优势是:使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。 示列如下: //第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器 always @ (posedge clk or negedge rst_n) //异步复位 if(!rst_n) current_state <= IDLE; else current_state <= next_state;//注意,使用的是非阻塞赋值 //第二个进程,组合逻辑always模块,描述状态转移条件判断 always @ (current_state) //电平触发,现态寄存器为敏感信号 begin next_state = x; //要初始化,使得系统复位后能进入正确的状态 //对次态寄存器进行阻塞赋值 case(current_state) S1: if(...) next_state = S2; //阻塞赋值 S2:if() next_state = S3. //阻塞赋值 …………. endcase end //第三个进程,同步时序always模块,格式化描述次态寄存器输出 always @ (posedge clk or negedge rst_n)//异步复位 begin ...//初始化 case(next_state) //次态寄存器作为CASE后的表达式 S1: out1 <= 1'b1; //对输出进行赋值,注意是非阻塞逻辑 S2: out2 <= 1'b1; ……….. default:... //default的作用是免除综合工具综合出锁存器。 endcase end 有几个地方需要再注意一下: 1.注意三个进程中使用的赋值方式:只有第二个进程中用阻塞赋值,其他的地方都用非阻 塞赋值 2.注意两个进程的case表达式:第二个进程用current_state作为表达式,第三个进程用

FPGA状态机学习笔记(verilog)

FPGA之有限状态机学习笔记 有限状态机(FSM)是由寄存器组合组合逻辑构成的硬件时序电路。FSM 的状态只可能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态。 Mealy型FSM的下一个状态不仅取决于当前所在状态,还取决于各个输入值。 Moore型FSM的下一个状态只取决于当前状态。 Verilog HDL可以用很多方法描述FSM,最常用的是用always语句和case 语句。FSM常用模型有Gray和独热码两种,对于用FPGA实现的FSM建议采用独热码。因为采用独热码可省下许多组合电路的使用,提高电路的速度和可靠性,且总的单元数并无显著增加。用Verilog语言描述FSM,可以充分发挥硬件描述语言的抽象建模能力。 有限状态机设计的一般步骤: (1)、逻辑抽象,得出状态转换图 (2)、状态化简 (3)、状态分配 (4)、选定触发器的类型并求出状态方程、驱动方程和输出方程 (5)、按照方程得出逻辑图

以下就是分别用独热码和Gray码实现上述状态的源程序: 采用独热码源程序: module fsm( Clock, Reset, A,B,C,D,E,Multi,Contig,Single ); input Clock; input Reset; input A,B,C,D,E; output Multi,Contig,Single; reg Multi; reg Contig; reg Single; parameter [6:0] S1=7'b0000001, S2=7'b0000010, S3=7'b0000100, S4=7'b0001000, S5=7'b0010000, S6=7'b0100000, S7=7'b1000000; parameter U_DL Y=1;

verilog状态机编写技巧

时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息。 状态机采用VerilogHDL语言编码,建议分为三个always段完成。这是为什么呢? 设计FSM的方法和技巧多种多样,但是总结起来有两大类:第一种,将状态转移和状态的操作和判断等写到一个模块(process、block)中。另一种是将状态转移单独写成一个模块,将状态的操作和判断等写到另一个模块中(在Verilog代码中,相当于使用两个“always”block)。其中较好的方式是后者。其原因如下。 首先FSM和其他设计一样,最好使用同步时序方式设计,好处不再累述。而状态机实现后,状态转移是用寄存器实现的,是同步时序部分。状态的转移条件的判断是通过组合逻辑判断实现的,之所以第二种比第一种编码方式合理,就在于第二种编码将同步时序和组合逻辑分别放到不同的程序块(process,block)中实现。这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。 三段式建模描述FSM的状态机输出时,只需指定case敏感表为次态寄存器,然后直接在每个次态的case分支中描述该状态的输出即可,不用考虑状态转移条件。 三段式描述方法虽然代码结构复杂了一些,但是换来的优势是使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA/CPLD等可编程逻辑器件上的综合与布局布线效果更佳。 示例如下: //第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器 always @ (posedge clk or negedge rst_n) //异步复位 if(!rst_n) current_state <= IDLE; else current_state <= next_state;//注意,使用的是非阻塞赋值 //第二个进程,组合逻辑always模块,描述状态转移条件判断 always @ (current_state) //电平触发 begin next_state = x; //要初始化,使得系统复位后能进入正确的状态 case(current_state) S1: if(...) next_state = S2; //阻塞赋值 ... endcase end //第三个进程,同步时序always模块,格式化描述次态寄存器输出 always @ (posedge clk or negedge rst_n) ...//初始化 case(next_state)

让Verilog仿真状态机时可以显示状态名

让Verilog仿真状态机时可以显示状态名 Situation: 我们平时使用Verilog 进行状态机编码时,通常使用parameter 对状态名进行定义,这样写Case 语句的时候就不会对这一串10 摸不着头脑。 可是通常这样做的话,在Modelsim 里看到的还是一串10,使排错非常困难, 特别是在用OneHot 编码的时候,就看到一串0 中间的一个1 #_# 简直要疯掉。Question: 我们可不可以像VHDL 一样,在仿真的时候看到状态名字,而不仅 仅是状态编码呢?答案当然是可以的拉,事在人为嘛!Solution1:另外定义一个 reg: state_name,长度根据状态名称长度而改变(状态名称字符数x8);在每个 状态执行的语句中加入state_name = ‘IDLE’;类似的一句语句;仿真时添加 state_name 进行观察,使用ASCII Radix。Solution2:使用如下语句:代码:`ifdef SIMULATION parameter S_idle = ‘idle’;parameter S_decode = ‘decode’;parameter S_start = ‘start‘;parameter S_wait = ‘wait’; parameter state_wid_msb = 47; `else parameter S_idle = 4’b0001; parameter S_decode = 4’b0010;parameter S_start = 4’b0100; parameter S_wait = 4’b1000;parameter state_wid_msb = 3; `endif reg [state_wid_msb:0] state;只要在仿真的时候`define SIMULATION 就可以了。一样 用ASCII Radix 查看。 tips:感谢大家的阅读,本文由我司收集整编。仅供参阅!

相关主题
文本预览
相关文档 最新文档