数字集成电路设计-12-状态机的四种写法
引言
在实际的数字电路设计中,状态机是最常用的逻辑,而且往往是全部逻辑的核心部分,所以状态机的质量,会在比较大的程度上影响整个电路的质量。
本小节我们通过一个简单的例子(三进制脉动计数器)来说明一下状态机的4中写法。
1,模块功能
由于我们的目的在于说明状态机的写作方式,所以其逻辑越简单有利于理解。就是一个简单的脉动计数器,每个三个使能信号输出一个标示信号。
2,一段式
状态机的写法,一般有四种,即一段式,两段式,三段式,四段式。对于一段式的写法,整个状态机的状态转移、转移条件、对应状态的输出都写在一个always块里,故称‘一段式’。那么,脉动计数器状态机的一段式写法该怎么写呢?如下所示:
/*
* file : fsm1.v
* author: Rill
* date : 2014-05-11
*/module Mfsm1
(
clk,
rst,enable,
done
);input wire clk;
input wire rst;
input wire enable;
output reg done;parameter s_idle = 4'd0;
parameter s_1 = 4'd1;
parameter s_2 = 4'd2;
parameter s_3 = 4'd3;reg [3:0] state;always @(posedge clk)
beginif(rst)begindone <=1'b0;state <= s_idle;endelsebegincase(state)s_idle:beginif(enable)state <= s_1;done <= 1'b0;end s_1:beginif(enable)state <= s_2;done <= 1'b0;end s_2:beginif(enable)beginstate <= s_3;done <= 1'b1;endelsebegindone <= 1'b0;endends_3:beginstate <= s_idle;done <= 1'b0;enddefault:beginstate <= s_idle;done <= 1'b0;endendcaseend
endendmodule
3,两段式
状态机的另外一种写法是‘两段式’的。两段式的写法,整个状态机由两个always块组成,第一个块只负责状态转移,第二个块负责转移条件和对应状态的输出。其中第一个块是时序逻辑,第二个块是组合逻辑。脉动计数器状态机的两段式写法又是怎样的呢?
/*
* file : fsm2.v
* author: Rill
* date : 2014-05-11
*/module Mfsm2
(
clk,
rst,enable,
done
);input wire clk;
input wire rst;
input wire enable;
output reg done;parameter s_idle = 4'd0;
parameter s_1 = 4'd1;
parameter s_2 = 4'd2;
parameter s_3 = 4'd3;reg [3:0] current_state;
reg [3:0] next_state;always @(posedge clk)
beginif(rst)begincurrent_state <= s_idle;endelsebegincurrent_state <= next_state;end
endalways @(*)
begincase(current_state)s_idle:beginif(enable)next_state = s_1;done = 1'b0;end s_1:beginif(enable)next_state = s_2;done = 1'b0;end s_2:beginif(enable)next_state = s_3;done = 1'b0;ends_3:beginnext_state = s_idle;done = 1'b1;enddefault:beginnext_state = s_idle;done = 1'b0;endendcase
endendmodule
4,三段式
从上面可以看出,两段式的写法是从一段式发展而来的,将一段式的写法中将状态转移部分提取出来,作为一个独立的always块,就变成了两段式。按照这个思路继续推进,如果将两段式的第二个块中的转移条件提取出来,也作为一个独立的块,就变成了‘三段式’,三段式的写法中,状态转移块是时序逻辑,转移条件块是组合逻辑,对应状态的输出是时序逻辑。那么,脉动计数器状态机的三段式写法是怎样的呢?
/*
* file : fsm3.v
* author: Rill
* date : 2014-05-11
*/module Mfsm3
(
clk,
rst,enable,
done
);input wire clk;
input wire rst;
input wire enable;
output reg done;parameter s_idle = 4'd0;
parameter s_1 = 4'd1;
parameter s_2 = 4'd2;
parameter s_3 = 4'd3;reg [3:0] current_state;
reg [3:0] next_state;always @(posedge clk)
beginif(rst)begincurrent_state <= s_idle;endelsebegincurrent_state <= next_state;end
endalways @(*)
begincase(current_state)s_idle:beginif(enable)next_state = s_1;ends_1:beginif(enable)next_state = s_2;ends_2:beginif(enable)next_state = s_3;ends_3:beginnext_state = s_idle;enddefault:beginnext_state = s_idle;endendcase
endalways @(posedge clk)
beginif(rst)begindone <= 1'b0;endelsebegincase(next_state)s_idle:begindone <= 1'b0;end s_1:begindone <= 1'b0;end s_2:begindone <= 1'b0;ends_3:begindone <= 1'b1;enddefault:begindone <= 1'b0;endendcaseendendendmodule
5,四段式
上面的三种状态机的写法是我们经常提到的,也是经典的三种。这三种写法在逻辑上是完全等价的,也就是是说,无论采用哪种写法,模块的功能都是一样的,但前两种一般只出现在教科书中,在实际的项目中是很少见到的。原因在于生成网表的综合器,由于目前的综合器还不够智能,其优化算法对三种写法的敏感度不同,造成最终生成的电路有所区别,有时候区别较大,尤其是对于复杂的状态机。无数血与泪的实践证明,使用前面两种写法生成的电路在时序、性能、功耗和面积等方面的表现都不如三段式的写法,所以即使三段式的写法会让你多敲几次键盘,在实际的电路设计中尽量采用三段式的写法来描述状态机,多敲的那几次键盘换来的电路质量的提高是完全值得的。
俗话说,“没有最好,只有更好”。三段式的写法是不是最好的呢?我认为不见得如此。上面说到,如果采用三段式的写法,代码会变长,如果是大的状态机,结果会更明显。那么,有没有一种写法,既能产生优质的电路,又能少敲几次键盘呢?答案是肯定的。
仔细观察上面三种写法,你会发现,无论是哪种写法,都会使用case语句,case语句不仅占用的代码行数最多,而且综合器对case语句还有不同的解析(full case和parallel case),如果我们将三段式的写法中的case语句换成assign语句,并将状态转移块进一步将当前状态和下一个状态拆分开,就变成了“四段式”,四段式的写法由状态识别,状态转移,转移条件和对应状态的输出四部分组成。那么,脉动计数器状态机四段式的写法又是如何实现的呢?
/*
* file : fsm4.v
* author: Rill
* date : 2014-05-11
*/module Mfsm4
(
clk,
rst,enable,
done
);input wire clk;
input wire rst;
input wire enable;
output done;parameter s_idle = 4'd0;
parameter s_1 = 4'd1;
parameter s_2 = 4'd2;
parameter s_3 = 4'd3;reg [3:0] current_state;wire c_idle = (current_state == s_idle);
wire c_1 = (current_state == s_1);
wire c_2 = (current_state == s_2);
wire c_3 = (current_state == s_3);wire n_idle = c_3;
wire n_1 = c_idle & enable;
wire n_2 = c_1 & enable;
wire n_3 = c_2 & enable;wire [3:0] next_state = {4{n_idle}} & s_idle |{4{n_1}} & s_1 |{4{n_2}} & s_2 |{4{n_3}} & s_3;always @(posedge clk)
beginif(rst)current_state <= s_idle;else if(n_idle | n_1 | n_2 | n_3)current_state = next_state;endassign done = c_3;
endmodule
6,验证
通过对比,我们很容易就会发现,采用四段式写法写出来的状态机,代码数量会减少很多,不仅如此,由于使用的语句类型减少了(只有赋值语句),生成电路的质量也会有所改善。那是否在进行电路设计的时候采用四段式的写法就没有缺点了呢?还有句俗话叫“金无足赤,人无完人”,由于四段式的写法将状态机拆分的过于零散,以至于综合器都识别不出来它是一个状态机了,所以在做覆盖率(coverage)分析的时候,分析工具只会按一般的逻辑进行分析,各个状态之间的转换概率就分析不出来了。
既然状态机有这么多种写法,在实际工作中采用哪一种呢?我认为三段式和四段式都是可以接受的(我个人习惯四段式的写法)。如果将来有一天综合器对四种写法综合出来的电路都差不多,那读者就可以根据自己的喜好来任意选择了。
上面提到,无论采用哪种写法,模块实现的功能都是完全相同的,倒底是不是呢?我们需要写一个简单的测试激励(testbench)来验证一下。
/*
* file : tb.v
* author: Rill
* date : 2014-05-11
*/module tb;reg clk;
reg rst;
reg enable;
wire done1;
wire done2;
wire done3;
wire done4;Mfsm1 fsm1
(
.clk(clk),
.rst (rst),
.enable(enable),
.done(done1)
);Mfsm2 fsm2
(
.clk(clk),
.rst (rst),
.enable(enable),
.done(done2)
);Mfsm3 fsm3
(
.clk(clk),
.rst (rst),
.enable(enable),
.done(done3)
);Mfsm4 fsm4
(
.clk(clk),
.rst (rst),
.enable(enable),
.done(done4)
);always #1 clk = ~clk;integer loop;initial
beginclk = 0;rst = 0;enable = 0;loop = 0;repeat (10) @(posedge clk);rst = 1;repeat (4) @(posedge clk);rst = 0;repeat (100) @(posedge clk);for(loop=1;loop<10;loop=loop+1)beginenable = 1;@(posedge clk);enable = 0;@(posedge clk);endrepeat (100) @(posedge clk);$stop;endendmodule
7,modelsim下的波形
8,ncsim的波形
上面是用windows下的modelsim得到的仿真波形,如果我们用ncsim(IUS),并且在Linux下,我们最好写一个简单的脚本来进行仿真,提高工作效率。
#! /bin/bash#
# fsm.sh
# usage: ./fsm.sh c/w/r
# Rill create 2014-09-03
#TOP_MODULE=tbtcl_file=run.tclif [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fiif [ $1 == "c" ]; then
echo "compile lib..."
ncvlog -f ./vflist -sv -update -LINEDEBUG;
ncelab -delay_mode zero -access +rwc -timescale 1ns/10ps ${TOP_MODULE}
exit 0
fiif [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}if [ $1 == "w" ];then
echo "open wave..."
echo "database -open waves -into waves.shm -default;" >> ${tcl_file}
echo "probe -shm -variable -all -depth all;" >> ${tcl_file}
echo "run" >> ${tcl_file}
echo "exit" >> ${tcl_file}
fiif [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim ${TOP_MODULE} -input ${tcl_file}
fiecho "$(date) sim done!"
运行脚本:
./fsm.sh c
./fsm.sh w
执行:
simvision wave/wave.trn
即可得到仿真波形,如下所示:
从中可以看出,ncsim和modelsim得到的仿真波形有所不同。原因在于前面的三种三段式写法是寄存器输出,第四种是组合逻辑输出。
数字集成电路设计-12-状态机的四种写法相关推荐
- VerilogHDL(1)数字集成电路设计方法概述
一.数字集成电路设计方法概述 2.什么是硬件描述语言,其主要的作用是什么? 硬件描述语言是一种用形式化方式来描述数字电路和系统的语言. 它的主要作用是:数字电路系统的设计者利用这种语言可以从上层到下层 ...
- 数字集成电路设计简介及设计方法
简介 数字集成电路(Digital Integrated Circuits,DIC)是一种能够处理数字信号的电路.它由多个数字逻辑电路元件组成,包括逻辑门.寄存器.计数器.加法器.乘法器等.数字集成电 ...
- 学以致用深入浅出数字信号处理 pdf_Robei |《数字集成电路设计》正式出版啦
原标题:Robei |<数字集成电路设计>正式出版啦 1.背景 <数字集成电路设计>作为电子信息.自动化.微电子.计算机.通信.电子工程等学科专业必修的数字电路技术课程 ,自2 ...
- java正则校验密码 长度不少于8位且至少包含大写字母、小写字母、数字和特殊符号中的四种组合 或者 其中任意三种组合
java正则校验密码必须是包含大小写字母.数字.特殊符号的8位以上四种组合 或者 其中任意三种组合 一.排除法和详细解释 1.排除大写字母.小写字母.数字.特殊符号中1种组合.2种组合.3种组合,那么 ...
- 数字集成电路设计(一、Verilog HDL数字集成电路设计方法概述)
文章目录 集成电路发展 HDL产生 HDL分类 Verilog HDL的发展 Verilog HDL与VHDL Verilog HDL在数字集成电路设计中的优点 组合逻辑电路原理图设计和Verilog ...
- 【笔记】 数字集成电路设计(一)
[笔记] 数字集成电路设计 书籍:<数字集成电路--电路.系统与设计>(第二版) 第一章 引论 1. 数字设计中需解决的问题 摩尔定律 技术突破才能推动摩尔定律 特征尺寸 28nm是传统制 ...
- 数字集成电路设计中------各种工程师职责
数字集成电路设计实现流程是个相当漫长的过程,拿手机基带芯片为例,对于3G, 4G, 5G, 工程师最初见到的是无数页的协议文档. 架构师要根据协议来确定:协议的哪些部分可以用软件实现,哪些部分需要用硬 ...
- 入门数字集成电路设计系列(一)——Modelsim安装及破解过程记录
入门数字集成电路设计系列(一) #Modelsim破解教程(记录) Modelsim是由 Mentor Graphics 公司开发的软件,它是世界最优秀的Verilog HDL语言仿真工具,是FPGA ...
- 数字集成电路设计的流程1
数字集成电路设计的流程 芯片验证属于前端 每个阶段的工作 使用的EDA工具,Linux系统(lincense) 三家软件公司,Mentor(questasim).Synopsys(VCS).Caden ...
最新文章
- oracle和ibatis学习
- win server2008搭建ftp服务器
- C 语言编程 — 高级数据类型 — 枚举
- 这是一个测试rss的内容哦
- 官网拉取fuchsia代码
- C++数组与指针回顾总结
- lua菜鸟教程_Lua语言学习
- react-性能优化
- python网络爬虫系列(六)——数据提取 lxml模块
- c语言程序设计授课进度安排表,C语言程序设计教学大纲、教学计划进度简表
- 第10-11讲 后端
- jQuery 图片放大预览插件
- 洛谷——P1590 失踪的7
- Linux 用户管理
- python语言实现医院管理系统
- 架构 - 5种常见的软件架构
- 【DB宝41】监控利器PMM的使用--监控MySQL、PG、MongoDB、ProxySQL等
- (安卓免费抓包软件)安卓7以上版本微信内部无法抓包的完美解决方案
- 利率浮动幅度bp什么意思,浮动利率bps换算百分比
- 山姆公司关于营销培训方案
热门文章
- 预测分析·民宿价格预测baseline
- 学习笔记(05):区块链应用案例-区块链金融应用-保险
- python怎么算阶乘_python计算阶乘
- 【大屏设计】数据大屏间距那点事-距离产生美
- java丐帮_java多线程学习笔记(八)
- 有生之年转ta系列4pc手机图形api介绍
- echarts tooltip提示框 自定义小圆点(颜色、形状和大小等等)
- 用HTML5+CSS实现3d动画立方体
- 【工利其器】必会工具之 Source Insight篇
- 【MATLAB教程案例7】基于Gardner环的定时误差检测matlab仿真