状态机的描述方法案例分析(一段式、二段式、三段式)
上篇博文讲了:FPGA中有限状态机的状态编码采用格雷码还是独热码?
那篇博文讲了状态机的状态编码是用格雷码还是独热码的问题,以及两者之间的优劣。状态机的描述方式采用的是一段式描述方式,也就是将整个状态机全部写到一个always模块中去。
这篇博文仍用上篇博文的案例,说说状态机的描述方法。一段式的描述方法、二段式以及三段式,并比较三者之间的功能仿真情况,最后真心吐露这个案例的状态转移图的疑问?不能把有问题的地方回避,我想我不要做这样的人。
首先看看状态机的描述方法,和编码方式,这两段描述借鉴:基于Verilog HDL的有限状态机,人家说的不错,我也懒着码字了。
状态机的描述方法
状态机的描述方法多种多样,将整个状态机写到1个always 模块里,在该模块中既描述状态转移,又描述状态的输入和输出,这种写法一般被称为一段式FSM 描述方法;
还有一种写法是使用两个always模块,其中一个always 模块采用同步时序的方式描述状态转移,而另一个模块采用组合逻辑的方式判断状态转移条件,描述状态转移规律,这种写法被称为两段式FSM 描述方法;
还有一种写法是在两段式描述方法的基础上发展而来的,这种写法使用3 个always模块,一个always 模块采用同步时序的方式描述状态转移,一个采用组合逻辑的方式判断状态转移条件,描述状态转移规律,第三个always 模块使用同步时序电路描述每个状态的输出,这种写法称为三段式写法。
状态机的状态编码
二进制码(Binary)和格雷码(Gray)属于压缩状态编码,这种编码的优点是使用的状态向量最少,但是需要较多的逻辑资源用来状态译码。二进制码从一个状态转换到相邻状态时,可能有多个比特位发生变化,易产生中间状态转移问题,状态机的速度也要比采用其它编码方式慢。格雷码两个相邻的码值仅有一位就可区分,这将会减少电路中相邻物理信号线同时变化的情况,因而可以减少电路中的电噪声。Johnson码也有同样的特点,但是要用较多的位数。
独热码(One-hot)指对任意给定的状态,状态寄存器中只有l位为1,其余位都为0。n状态的有限状态机需要n个触发器,但这种有限状态机只需对寄存器中的一位进行译码,简化了译码逻辑电路,额外触发器占用的面积可用译码电路省下来的面积抵消。当设计中加入更多的状态时,译码逻辑没有变得更加复杂,有限状态机的速度仅取决于到某特定状态的转移数量,而其它类型有限状态机在状态增加时速度会明显下降。独热码还具有设计简单、修改灵活、易于综合和调试等优点。独热码相对于二进制码,速度快但占用面积大。
给出实际案例:
下面是一个状态转移图,我们接下来就这个状态转移图来用不同的描述方式来描述。
1)一段式描述方法:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 21:27:04 09/02/2018
// Design Name:
// Module Name: fsm
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fsm(input Clock,input rst_n,input A,output F,output G);
reg F, G;
reg [3:0] state;parameter Idle = 4'b1000, Start = 4'b0100, Stop = 4'b0010, Clear = 4'b0001;always @(posedge Clock) beginif(!rst_n) beginstate <= Idle;F <= 1'b0;G <= 1'b0;
end
elsecase(state)Idle: beginif(A) beginstate <= Start;G <= 1'b0;endelsestate <= Idle;endStart: beginif(!A)state <= Stop;elsestate <= Start;endStop: beginif(A) beginstate <= Clear;F <= 1'b1;endelsestate <= Stop;endClear: beginif(!A)beginstate <= Idle;F <= 1'b0;G <= 1'b1;endelsestate <= Clear;enddefault: state <= Idle;endcase end endmodule
给出测试文件,测试文件在这个案例中通用:
`timescale 1ns / 1ps// Company:
// Engineer:
//
// Create Date: 23:39:28 09/02/2018
// Design Name: fsm
// Module Name: G:/modelsim_file/fsm01/fsm_tb.v
// Project Name: fsm01
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: fsm
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// module fsm_tb;// Inputsreg Clock;reg rst_n;reg A;// Outputswire F;wire G;// Instantiate the Unit Under Test (UUT)fsm uut (.Clock(Clock), .rst_n(rst_n), .A(A), .F(F), .G(G));initial begin// Initialize Inputs rst_n = 0;A = 0;#30 A = 1;rst_n = 1;#30 A = 0;#20 A = 1;#20 A = 0;// Wait 100 ns for global reset to finish#100;endinitial beginClock = 0; forever #10 Clock = ~Clock;endendmodule
功能仿真:
两段式描述方法:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 21:27:04 09/02/2018
// Design Name:
// Module Name: fsm
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fsm(input Clock,input rst_n,input A,output F,output G);
reg F, G;
reg [3:0] pre_state;
reg [3:0] next_state;parameter Idle = 4'b1000, Start = 4'b0100, Stop = 4'b0010, Clear = 4'b0001;//第一个过程,同步时序always块,描述状态转移方程
always @(posedge Clock) beginif(!rst_n)pre_state <= Idle;
elsepre_state <= next_state;end
//第二个过程,组合逻辑always块,描述激励方程以及输出方程
always @(pre_state or A or rst_n) begincase(pre_state)Idle:beginif(!rst_n) beginnext_state = Idle;F = 1'b0;G = 1'b0;endelse if(A) beginnext_state = Start;G = 1'b0;endelse beginnext_state = Idle;end
endStart: beginif(!rst_n) beginnext_state = Idle;F = 1'b0;G = 1'b0;endelse if(!A) beginnext_state = Stop;endelse beginnext_state = Start;end
endStop: beginif(!rst_n) beginnext_state = Idle;F = 1'b0;G = 1'b0;endelse if(A) beginnext_state = Clear;F = 1'b1;endelse beginnext_state = Stop;end
endClear: beginif(!rst_n) beginnext_state = Idle;F = 1'b0;G = 1'b0;endelse if(!A) beginnext_state = Idle;F = 0;G = 1;endelse beginnext_state = Clear;end
enddefault: beginnext_state = Idle;
endendcaseendendmodule
三段式描述:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 21:27:04 09/02/2018
// Design Name:
// Module Name: fsm
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module fsm(input Clock,input rst_n,input A,output F,output G);
reg F, G;
reg [3:0] pre_state;
reg [3:0] next_state;parameter Idle = 4'b1000, Start = 4'b0100, Stop = 4'b0010, Clear = 4'b0001;//第一个过程,同步时序always块,描述状态转移方程
always @(posedge Clock) beginif(!rst_n)pre_state <= Idle;
elsepre_state <= next_state;end
//第二个过程,组合逻辑always块,描述激励方程
always @(pre_state or A or rst_n) begin
case(pre_state)Idle: beginif(!rst_n) next_state = Idle;else if(A) next_state = Start;else next_state = Idle;
endStart: beginif(!rst_n) next_state = Idle;else if(!A) next_state = Stop;else next_state = Start;
endStop: beginif(!rst_n) next_state = Idle;else if(A) next_state = Clear;else next_state = Stop;
endClear: beginif(!rst_n) next_state = Idle;else if(!A) next_state = Idle;else next_state = Clear;
enddefault: next_state = Idle;endcaseend
//第三个always块,描述输出方程
always @(pre_state or A or rst_n) begincase(pre_state)Idle:beginif(!rst_n) beginF = 1'b0;G = 1'b0;endelse if(A) beginG = 1'b0;endelse begin;end
endStart: beginif(!rst_n) beginF = 1'b0;G = 1'b0;endelse if(!A) begin;endelse begin;end
endStop: beginif(!rst_n) beginF = 1'b0;G = 1'b0;endelse if(A) beginF = 1'b1;endelse begin;end
endClear: beginif(!rst_n) beginF = 1'b0;G = 1'b0;endelse if(!A) beginF = 0;G = 1;endelse begin;end
enddefault: begin;
endendcaseendendmodule
功能仿真:
可见,三种描述方式的仿真图都是一样的,说明了完成同样的功能。
但是从代码的简洁度来看,就这个小状态转移图来说,无疑,一段式的描述方式是最为简单的。但是随着项目的复杂度增高,这种描述方式不便于维护和阅读。
所以呢?要综合来看,不能说哪一种一定好,哪一种一定坏,要根据实际情况而定。
最后我要提出的问题,就是Clear这个状态向Idle这个状态转移的条件:从状态图上看,注意图中的状态图的复位我用rst_n代替,这样更人性化!继续:从状态图上看,是!rst_n或!A有效时,向Idle状态转移,并且输出是F = 0 ,且 G =1;
但是从原作者的一段式代码中,我们可以看出,复位信号rst_n的优先级别要高,如果复位了,那么状态肯定转向Idle,且此时,输出F=0且G=0.这明显和状态转移图中的意思不一样啊,我们推测状态转移图写法有误,所以这里我个人默认复位信号有限,其次是输入A和当前状态决定输出。也就是说,如果复位信号无效时,当前状态为Clear且 !A有效,那么输出就是F = 0 ,且 G =1,并且状态转向Idle.
状态机的描述方法案例分析(一段式、二段式、三段式)相关推荐
- 大型网站技术架构:核心原理与案例分析阅读笔记二
大型网站技术架构:核心原理与案例分析阅读笔记二 网站架构设计时可能会存在误区,其实不必一味追随大公司的解决方案,也不必为了技术而技术,要根据本公司的实际情况,制定适合本公司发展的网站架构设计,否则会变 ...
- python财务案例分析考试答案_《财务案例分析》作业及答案(三次).
<财务案例分析>作业一 一.单选题(每题 2 分) 1. 企业投资者进行财务分析的根本目的是关心企业的( A ) A .盈利能力 B .营运能力 C .偿债能力 D .增长能力 2. 公司 ...
- python财务案例分析考试答案_《财务案例分析》作业及答案(三次)
<财务案例分析>作业一 一.单选题(每题 2 分) 1. 企业投资者进行财务分析的根本目的是关心企业的( A ) A .盈利能力 B .营运能力 C .偿债能力 D .增长能力 2. 公司 ...
- 抢红包案例分析以及代码实现(三) 侵立删
转自:https://mp.weixin.qq.com/s/Pp-nCYrzXXXfLcFFS_ttWg 前文回顾 抢红包案例分析以及代码实现(一) 抢红包案例分析以及代码实现(二) 接下来我们使用乐 ...
- html三段式布局,运用三段式框架,教你轻松应对10分钟即兴演讲!
即兴演讲不宜篇幅过长,一般人在很短的时间也不可能构思出内容复杂的宏篇巨论.因此,即兴演讲宜简短精炼,结构简单,一般为单线条式的结构,或横向的以事物的几个方面为纲,或纵向的以事物的发展过程为目,按逻辑思 ...
- MBA案例分析(人员培训二)
[案例三]美国斯图·伦纳德奶制品商店:访问竞争对手美国斯图·伦纳德奶制品商店的经理斯图·伦纳德培训教育中层干部,使他们成为零售业务和竞争分析方面的专家,成为主人翁.成为胜者的方法很独特,其做法就是访问 ...
- 机器视觉——OpenCV案例分析基础(二)(给图片打马赛克与图像的运算处理)
给图片打马赛克与图像的运算处理 一.理论分析 二.代码分析 2.1 对图像全局采用马赛克处理 2.2 局部马赛克 2.3 对图片进行运算处理 2.3.1 图像的或运算 2.3.2 图像的与运算 2.3 ...
- 软考系统架构师笔记-案例分析重点(二)
系统架构设计非功能需求主要有4类:操作性需求.性能需求.安全性需求.文化需求: 性能需求:响应时间.吞吐量.准确性.有效性.资源利用率.系统完成任务效率等.可靠性.可用性等指标也能归此类. 安全性需求 ...
- S7-200SMART案例分析——运动控制编程(二)
类似于LDOFF,LDOFF是创建新的参考点(零点),而LDPOS是可以将位置更改为任意坐标,例如将50的位置设置为60或者其他值 AXISx_LDPOS 子例程(加载位置)将运动轴中的当前位置值更改 ...
最新文章
- linux 空格函数,linux c语言的split函数和空格处理函数
- 36.Silverlight中播放视频和打印文档【附带源码实例】
- ES6中解构赋值深入解读
- colab把数据放在content下面以及放在drive下面的训练速度比较
- 计算机二级和英语四六级是同一个账号吗,英语四六级考试和计算机考试的登录账号和密码一样吗?我好像混了,但是密码一直输不对,...
- [html] 写一个类似刮刮卡效果的交互,即鼠标划过时显示号码
- ZigBee MAC层(上)
- neo4j unwind
- 网御神州和北京邮电大学成立信息安全联合实验室(2007-07-04)
- linux 自学笔记
- Steinberg Cubase Elements 11 for Mac(音频处理软件)
- CUID卡写入错误数据被锁死——入坑NFC的一段经历
- Html的基本操作简介
- 假设检验实验和拟合优度检验练习题
- pdf添加水印的方法,pdf加水印步骤
- 利用 Eclipse Visual Editor 项目构建 GUI 应用程序
- 面试官喜欢问的 设计模式之观察者模式
- Pygame 官方文档 - Tutorials - 逐行的黑猩猩教程(Line By Line Chimp)
- 【C语言】实现双人控制的战斗小游戏
- 概念结构设计、逻辑结构设计、物理设计的区分