引言

在实际的数字电路设计中,状态机是最常用的逻辑,而且往往是全部逻辑的核心部分,所以状态机的质量,会在比较大的程度上影响整个电路的质量。

本小节我们通过一个简单的例子(三进制脉动计数器)来说明一下状态机的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-状态机的四种写法相关推荐

  1. VerilogHDL(1)数字集成电路设计方法概述

    一.数字集成电路设计方法概述 2.什么是硬件描述语言,其主要的作用是什么? 硬件描述语言是一种用形式化方式来描述数字电路和系统的语言. 它的主要作用是:数字电路系统的设计者利用这种语言可以从上层到下层 ...

  2. 数字集成电路设计简介及设计方法

    简介 数字集成电路(Digital Integrated Circuits,DIC)是一种能够处理数字信号的电路.它由多个数字逻辑电路元件组成,包括逻辑门.寄存器.计数器.加法器.乘法器等.数字集成电 ...

  3. 学以致用深入浅出数字信号处理 pdf_Robei |《数字集成电路设计》正式出版啦

    原标题:Robei |<数字集成电路设计>正式出版啦 1.背景 <数字集成电路设计>作为电子信息.自动化.微电子.计算机.通信.电子工程等学科专业必修的数字电路技术课程 ,自2 ...

  4. java正则校验密码 长度不少于8位且至少包含大写字母、小写字母、数字和特殊符号中的四种组合 或者 其中任意三种组合

    java正则校验密码必须是包含大小写字母.数字.特殊符号的8位以上四种组合 或者 其中任意三种组合 一.排除法和详细解释 1.排除大写字母.小写字母.数字.特殊符号中1种组合.2种组合.3种组合,那么 ...

  5. 数字集成电路设计(一、Verilog HDL数字集成电路设计方法概述)

    文章目录 集成电路发展 HDL产生 HDL分类 Verilog HDL的发展 Verilog HDL与VHDL Verilog HDL在数字集成电路设计中的优点 组合逻辑电路原理图设计和Verilog ...

  6. 【笔记】 数字集成电路设计(一)

    [笔记] 数字集成电路设计 书籍:<数字集成电路--电路.系统与设计>(第二版) 第一章 引论 1. 数字设计中需解决的问题 摩尔定律 技术突破才能推动摩尔定律 特征尺寸 28nm是传统制 ...

  7. 数字集成电路设计中------各种工程师职责

    数字集成电路设计实现流程是个相当漫长的过程,拿手机基带芯片为例,对于3G, 4G, 5G, 工程师最初见到的是无数页的协议文档. 架构师要根据协议来确定:协议的哪些部分可以用软件实现,哪些部分需要用硬 ...

  8. 入门数字集成电路设计系列(一)——Modelsim安装及破解过程记录

    入门数字集成电路设计系列(一) #Modelsim破解教程(记录) Modelsim是由 Mentor Graphics 公司开发的软件,它是世界最优秀的Verilog HDL语言仿真工具,是FPGA ...

  9. 数字集成电路设计的流程1

    数字集成电路设计的流程 芯片验证属于前端 每个阶段的工作 使用的EDA工具,Linux系统(lincense) 三家软件公司,Mentor(questasim).Synopsys(VCS).Caden ...

最新文章

  1. oracle和ibatis学习
  2. win server2008搭建ftp服务器
  3. C 语言编程 — 高级数据类型 — 枚举
  4. 这是一个测试rss的内容哦
  5. 官网拉取fuchsia代码
  6. C++数组与指针回顾总结
  7. lua菜鸟教程_Lua语言学习
  8. react-性能优化
  9. python网络爬虫系列(六)——数据提取 lxml模块
  10. c语言程序设计授课进度安排表,C语言程序设计教学大纲、教学计划进度简表
  11. 第10-11讲 后端
  12. jQuery 图片放大预览插件
  13. 洛谷——P1590 失踪的7
  14. Linux 用户管理
  15. python语言实现医院管理系统
  16. 架构 - 5种常见的软件架构
  17. 【DB宝41】监控利器PMM的使用--监控MySQL、PG、MongoDB、ProxySQL等
  18. (安卓免费抓包软件)安卓7以上版本微信内部无法抓包的完美解决方案
  19. 利率浮动幅度bp什么意思,浮动利率bps换算百分比
  20. 山姆公司关于营销培训方案

热门文章

  1. 预测分析·民宿价格预测baseline
  2. 学习笔记(05):区块链应用案例-区块链金融应用-保险
  3. python怎么算阶乘_python计算阶乘
  4. 【大屏设计】数据大屏间距那点事-距离产生美
  5. java丐帮_java多线程学习笔记(八)
  6. 有生之年转ta系列4pc手机图形api介绍
  7. echarts tooltip提示框 自定义小圆点(颜色、形状和大小等等)
  8. 用HTML5+CSS实现3d动画立方体
  9. 【工利其器】必会工具之 Source Insight篇
  10. 【MATLAB教程案例7】基于Gardner环的定时误差检测matlab仿真