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. word中输入公式方案

    如何开启word公式模式:“Alt”+"=" 1. 如何输入矩阵: 使用&链接行元素,@进行换行,空格键进行转换 如输出: 先开启公式模式:“Alt”+"=&qu ...

  2. MHA搭建及故障维护

    MHA是一种方便简单可靠的MySQL高可用架构,具体的介绍我在这里就不多说了,下面是我在网上找的一个教程,我在此基础上进行了一些修改: 大致步骤 (一).环境介绍 (二).用ssh-keygen实现四 ...

  3. pandas 1 基本介绍

    import numpy as np import pandas as pd pd.Series() 构造数据 s = pd.Series([1, 3, 5, np.nan, 44, 1]) prin ...

  4. Redis学习总结(3)——Redis整合Spring结合使用缓存实例

    摘要:本文介绍了如何在Spring中配置redis,并通过Spring中AOP的思想,将缓存的方法切入到有需要进入缓存的类或方法前面. 一.Redis介绍 什么是Redis? redis是一个key- ...

  5. 2016 10 27 考试 dp 向量 乱搞

    目录 20161027考试 T1: T2: T3: 20161027考试 考试时间 7:50 AM to 11:15 AM 题目 考试包 据说这是一套比较正常的考卷,,,嗯,,或许吧, 而且,,整个小 ...

  6. OpenStack 与 大数据的融合

        此处是hadoop 2.7.2以前 Hadoop 预留的一个 HDFS 文件系统的接口. 可以通过修改这里 将数据源的读取改为 Swift. 也可以通过修改 MR 源码 将数据抽取部分变换成 ...

  7. poj_2352树状数组

    因为y已经排好序了,用x坐标建立一维树状数组 #include<iostream> #include<cstdio> #include<cstring> using ...

  8. Random numbers

    Most computer programs do the same thing every time they execute, given the same inputs, so they are ...

  9. 安卓开发--AsyncTask

    package com.cnn.asynctask; import android.app.Activity; import android.content.Intent; import androi ...

  10. 实时监控Cat之旅~对Get和Post进行封装,支持分布式消息树

    对第三方接口的调用我们需要对GET和POST进行监控,看一些请求的执行是否成功,如A调用B,B调用C,C调用D,这一连串的东西需要我们使用cat进行记录,进行记录之后,我们可以很容易的发现请求响应的时 ...