FSM设计之一http://www.cnblogs.com/qiweiwang/archive/2010/11/28/1890244.html

  Moore型状态机与mealy型状态机相比,由于其状态输出仅与当前状态有关,而与输入无关,所以它可以避免由输入信号引起的毛刺,因此建议采用Moore型状态机。但是在实际的应用中,我们只需要对状态输出进行寄存,即在outputs后面加上一级输出寄存,就可以有效地避免毛刺的传播。

  Binary、gray-code编码使用最少的触发器,较多的组合逻辑。而one-hot 编码反之。由于CPLD更多的提供组合逻辑资源,而FPGA更多的提供触发器资源,所以CPLD 多使用gray-code,而FPGA 多使用one-hot编码。 另一方面,对于小型设计使用gray-code和binary编码更有效,而大型状态机使用one-hot更高效。 
   看synplicity的文档,推荐在24个状态以上会用格雷码,在5~24个状态会用独热码,在4个状态以内用二进制码,肯定独热码比二进制码在实现FSM部分会占更多资源,但是译码输出控制简单,所以如果状态不是太多,独热码较好。状态太少译码不会太复杂,二进制就可以了。状态太多,前面独热码所占资源太多,综合考虑就用格雷码了。

编码风格: 
1.  避免生成锁存器 
  一个完备的状态机(健壮性强)应该具备初始化(reset)状态和默认(default)状态。 当芯片加电或者复位后,状态机应该能够自动将所有判断条件复位,并进入初始化状态。需要注
明的一点是,大多数FPGA有GSR(Global Set/Reset)信号,当FPGA加电后,GSR信号拉高,对所有的寄存器,RAM等单元复位/置位,这时配置于FPGA的逻辑并未生效,所以不能保证正确的进入初始化状态。所以使用 GSR进入FPGA的初始化状态,常常会产生种种不必一定的麻烦。一般简单方便的方法是采用异步复位信号,当然也可以使用同步复位,但是要注意同步复位的逻辑设计。 
   状态机也应该有一个默认(default)状态,当转移条件不满足,或者状态发生了突变时,要能保证逻辑不会陷入“死循环”。这是对状态机健壮性的一个重要要求,也就是常说的要具备“自恢复”功能。对应于编码就是对 case,if-else 语句要特别注意,要写完备的条件判断语句。VHDL 中,当使用CASE语句的时候,要使用“When Others”建立默认状态。使用“IF...THEN...ELSE”语句的时候,要用在“ELSE”指定默认状态。 Verilog中, 使用“case”语句的时候要用“default”建立默认状态, 使用“if...else”语句的注意事项相似。 
     另外有一个技巧:大多数综合器都支持 Verilog 编码状态机的完备状态属性--“full case”。

2.  参数定义用 parameter 
  状态的定义用 parameter 定义,不推荐使用`define 宏定义的方式,因为‘define 宏定义在编译时自动替换整个设计中所定义的宏,而 parameter 仅仅定义模块内部的参数,定义的参数不会与模块外的其他状态机混淆。

3.  一定要使用”<=”非阻塞赋值方式 
  采用非阻塞赋值方式消除很多竞争冒险的隐患。

module gray
(
input clk,
input rst_n,
input a,
outputreg y
);
//
parameter s0 =2'b00,
s1 =2'b01,
s2 =2'b10,
s3 =2'b11;
//
reg [1:0] current_state;
reg [1:0] next_state;
//状态转移
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
current_state <= s0;
else
current_state <= next_state;
end
//状态译码逻辑
always @ (a or current_state)
begin
case(cs)
s0:
if(a==1'b1)
next_state =s1;
else
next_state=s0;
s1:
next_state = s2;
s2:
next_state = s3;
s3:
next_state = s0;
default:
next_state =s0;
endcase
end
//状态寄存输出
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
y <=1'b0;
elseif(next_state==s3)//输出与next_state有关
y <=!a;
else
y <=1'b0;
end

endmodule

one-hot编码

  one-hot顾名思义,指任何时候一个nbit的寄存器组中有且仅有1bit为1,其他n-1个寄存器值均为0。在状态机编码的范畴中,它就像是“一个萝卜一个坑”,每个状态都占用一个寄存器,该位为1时表示状态机进入该状态,为0时表示状态机不在该状态。因此,每个状态只用1bit即可表示出来。在进入一个新状态时,将原状态对应的寄存器位置0、新状态对应的寄存器位置1,以保证“one-hot”。

  在电路面积和速度方面,one-hot编码方式所占用的DFF资源要比binary编码多一些,n个状态要用n个DFF;但是这种编码方式由在状态译码的时候只需要用1bit参与状态译码,译码逻辑较小,生成的组合逻辑相应的较小。总体来说,在FPGA设计中,采用one-hot编码方式往往消耗的资源要比binary编码少。

  那么为什么one-hot编码方式在译码的时候只需要有1bit参与译码呢?我们知道,需要多少位参与状态译码和状态的表示方式很有关系,也就是说和何种方式去标识一个状态很有关系,如果一个状态用4bit表示,那么它在译码的时候就要用4bit,但是如果只有一个状态用1bit表示,则它参与译码时只需要1bit即可,所以,one-hot这种“一个萝卜一个坑”的结构决定了它在译码时每个状态只需要用一位参与译码。

  one-hot编码方式通常分为两类:一种是非index编码方式;一种是index编码方式。

module not_index_fsm
(
input clk,
input rst_n,
input [1:0] a,
output y
);
//
parameter U_DLY =1;
parameter s0 =10'b00_0000_0001,
s1 =10'b00_0000_0010,
s2 =10'b00_0000_0100,
s3 =10'b00_0000_1000,
s4 =10'b00_0001_0000,
s5 =10'b00_0010_0000,
s6 =10'b00_0100_0000,
s7 =10'b00_1000_0000,
s8 =10'b01_0000_0000,
s9 =10'b10_0000_0000;
//
reg [9:0] current_state;
reg [9:0] next_state;
reg [5:0] cnt;
//
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
current_state <= s0;
else
current_state <= #U_DLY next_state;
end
//
always @ (a,cnt,current_state)
begin
case(current_state)
s0:
case(a)
2'b00: next_state = s1;
2'b01: next_state = s2;
2'b10: next_state = s3;
2'b11: next_state = s4;
endcase
s1:
next_state = s9;
s2:
next_state = s5;
s3:
next_state = s6;
s4:
next_state = s8;
s5:
next_state = s6;
s6:
next_state = s7;
s7:
begin
if(cnt==6'h2f)
next_state = s9;
else
next_state = s7;
end
s8:
next_state = s9;
s9:
begin
if(cnt ==6'h3f)
next_state = s0;
else
next_state = s9;
end
default:
next_state = s0;
endcase
end
//
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
cnt <=6'b0;
elseif(next_state == s9)
cnt <= #U_DLY cnt+1'b1;
else
cnt <= #U_DLY 6'b0;
end

assign y = current_state[8];

endmodule

index编码方式:

module index_fsm
(
input clk,
input rst_n,
input [1:0] a,
output y
);
//
parameter U_DLY =1;
parameter s0 =0,
s1 =1,
s2 =2,
s3 =3,
s4 =4,
s5 =5,
s6 =6,
s7 =7,
s8 =8,
s9 =9;
//
reg [9:0] current_state;
reg [9:0] next_state;
reg [5:0] cnt;
//
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
state <=10'b0;
        state[s0] <= 1'b1;//because the coding of IDLE is 10'b1
else
current_state <= #U_DLY next_state;
end
//
always @ (a,cnt,current_state)
begin
next_state <=10'b0;//给next_state这样赋默认值综合后不会出现锁存器
case(1'b1)//synthesis parallel_case full_case
current_state[s0]:
case(a)
2'b00: next_state[s1] = 1'b1;
2'b01: next_state[s2] = 1'b1;
2'b10: next_state[s3] = 1'b1;
2'b11: next_state[s4] = 1'b1;
endcase
current_state[s1]:
next_state[s9] =1'b1;
current_state[s2]:
next_state[s5] =1'b1;
current_state[s3]:
next_state[s6] =1'b1;
current_state[s4]:
next_state[s8] =1'b1;
current_state[s5]:
next_state[s6] =1'b1;
current_state[s6]:
next_state[s7] =1'b1;
current_state[s7]:
begin
if(cnt==6'h2f)
next_state[s9] =1'b1;
else
next_state[s7] =1'b1;
end
current_state[s8]:
next_state[s9] =1'b1;
current_state[s9]:
begin
if(cnt ==6'h3f)
next_state[s0] =1'b1;
else
next_state[s9] =1'b1;
end
endcase
end
//
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
cnt <=6'b0;
elseif(next_state[s9] ==1'b1)
cnt <= #U_DLY cnt+1'b1;
else
cnt <= #U_DLY 6'b0;
end

assign y = current_state[s8];//在使用one-hot状态机某些情况下,可以将状态信号直接作为输出,从而节约逻辑资源,提供电路速度

endmodule

由上面的例子分析可知,非index编码的状态机在状态译码时使用了10位参与状态译码,index编码时只用了一位参与状态译码。而由前面的分析知道,one-hot编码的本质就是一个状态用一位表示,因此,index编码才能真正地反映出one-hot的本质。

  非index编码的状态机由于译码逻辑过多,在消耗资源级Fmax这两个指标上都不如index编码,因此,在使用one-hot编码时,推荐使用index编码的方式。

FSM之三--代码风格的更多相关文章

  1. Python 代码风格

    1 原则 在开始讨论Python社区所采用的具体标准或是由其他人推荐的建议之前,考虑一些总体原则非常重要. 请记住可读性标准的目标是提升可读性.这些规则存在的目的就是为了帮助人读写代码,而不是相反. ...

  2. .NET 项目代码风格要求

    原文:http://kb.cnblogs.com/page/179593/ 项目代码风格要求 PDF版下载:项目代码风格要求V1.0.pdf 代码风格没有正确与否,重要的是整齐划一,这是我拟的一份&l ...

  3. AngularJS之代码风格36条建议【一】(九)

    前言 其实在新学一门知识时,我们应该注意下怎么书写代码更加规范,从开始就注意养成一个良好的习惯无论是对于bug的查找还是走人后别人熟悉代码都是非常好的,利人利己的事情何乐而不为呢,关于AngularJ ...

  4. Visual Studio Code 使用 ESLint 增强代码风格检查

    前言 在团队协作开发中,为了统一代码风格,避免一些低级错误,应该设有团队成员统一遵守的编码规范.很多语言都提供了Lint工具来实现这样的功能,JavaScript也有类似的工具:ESLint.除了可以 ...

  5. plain framework 1 参考手册 入门指引之 代码风格

    代码风格 介绍 介绍 框架自身采用了google的C++风格,作者也鼓励在你的应用中使用此风格,有关此风格你可以查阅相关资料了解.下面是一段plain framework中的代码,以便大家参考: 你可 ...

  6. 对 JimmyZhang 老师的文章《项目代码风格要求》的一些个人观点

    Jimmy Zhang 老师是博客园中我最佩服的人之一,今天看了他的文章<项目代码风格要求>觉得大部分地方我都很认同,工作中也是强迫自己也要按照规范来编程.下面是我的一些个人观点,想贴出来 ...

  7. python代码风格-PEP8

    转载自http://www.douban.com/note/134971609/ Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下 ...

  8. Google HTML/CSS代码风格指南(中文版)

    原文链接:http://wncbl.cn/posts/c8e10815/ 看一下没什么印象,那就写一遍吧. 背景 本文档定义了HTML/CSS的编写格式和风格规则.它旨在提高合作和代码质量,并使其支持 ...

  9. .Net 项目代码风格要求小结

    代码风格没有正确与否,重要的是整齐划一,这是我拟的一份<.Net 项目代码风格要求>,供大家参考. 1. C# 代码风格要求1.1注释 类型.属性.事件.方法.方法参数,根据需要添加注释. ...

随机推荐

  1. 解决PNG图片在IE6中背景不透明方法_解决IE6中PNG背

    解决PNG图片在IE6中背景不透明方法_解决IE6中PNG背   目录 解决代码 解决png图片在html中 解决png作为网页背景-css 1.解决PNG图片在IE6中背景不透明的CSS与JS代码 ...

  2. centos安装nvidia驱动

    大部分 Linux 发行版都使用开源的显卡驱动 nouveau,对于 nvidia 显卡来说,还是闭源的官方驱动的效果更好.最明显的一点是,在使用 SAC 拾取震相的时候,使用官方显卡驱动在刷新界面的 ...

  3. Maven命令下载源码和javadocs

    1:Maven命令下载源码和javadocs 当在IDE中使用Maven时如果想要看引用的jar包中类的源码和javadoc需要通过maven命令下载这些源码,然后再进行引入,通过mvn命令能够容易的 ...

  4. Linux 程序包管理-RPM

    程序简介:  POSIX(Portable Openratin System)跨平台系统:不同操作系统平台的标准C库(glibc)都是遵循POSIX规范的,这样基于标准库开发程序的源代码可以夸平台编译 ...

  5. Linux用户与用户组

    Linux用户与用户组 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统. 用户的账号一方面可以帮助系统管 ...

  6. [terry笔记]11gR2_dataguard_保护模式切换

    保护模式切换 Maximum protection/availability/ performance 1. 首先查看当前的保护模式 SQL> select protection_mode,pr ...

  7. 现代C++ 基于范围的for和for_each语句

    现代C++中强调,使用基于范围的 for 循环(Visual studio 2012之后的),相比于旧版的 for 循环更整洁和易于使用,并且不容易发生意外错误.让我们一睹为快. 当然,使用前需要包含 ...

  8. python 与cpp接口编程

    (1)vc6下面生成dll学习 1.使用 VC6.0 生成 DLL新建项目 “Win32 Dynamic-Link Library”,输入项目名称,确定后选择 “A simple DLL projec ...

  9. jsp学习-分页功能的实现

    <%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8"%> < ...

  10. [P3097] [USACO13DEC] [BZOJ4094] 最优挤奶Optimal Milking 解题报告(线段树+DP)

    题目链接:https://www.luogu.org/problemnew/show/P3097#sub 题目描述 Farmer John has recently purchased a new b ...