Verilog HDL设计进阶:有限状态机的设计原理及其代码风格_zt

http://www.21ic.com/app/eda/201308/189781_1.htm

由于Verilog HDL和 VHDL 行为描述用于综合的历史还只有短短的几年,可综合风格的Verilog HDL 和VHDL的语法只是它们各自语言的一个子集。又由于HDL的可综合性研究近年来非常活跃,可综合子集的国际标准目前尚未最后形成,因此各厂商的综合器所支持的HDL子集也略有所不同。

本书中有关可综合风格的Verilog HDL的内容,我们只着重介绍RTL级、算法级和门级逻辑结构的描述,而系统级(数据流级)的综合由于还不太成熟,暂不作介绍。

由于寄存器传输级(RTL)描述是以时序逻辑抽象所得到的有限状态机为依据的,所以把一个时序逻辑抽象成一个同步有限状态机是设计可综合风格的Verilog HDL模块的关键。

在本章中我们将通过各种实例由浅入深地来介绍各种可综合风格的Verilog HDL模块,并把重点放在时序逻辑的可综合有限状态机的Verilog HDL设计要点。至于组合逻辑,因为比较简单,只需阅读典型的用Verilog HDL描述的可综合的组合逻辑的例子就可以掌握。

为了更好地掌握可综合风格,还需要较深入地了解阻塞和非阻塞赋值的差别和在不同的情况下正确使用这两种赋值的方法。只有深入地理解阻塞和非阻塞赋值语句的细微不同,才有可能写出不仅可以仿真也可以综合的Verilog HDL模块。

只要按照一定的原则来编写代码就可以保证Verilog模块综合前和综合后仿真的一致性。符合这样条件的可综合模块是我们设计的目标,因为这种代码是可移植的,可综合到不同的FPGA和不同工艺的ASIC中,是具有知识产权价值的软核。

4.4.1 有限状态机(FSM)设计原理

有限状态机是由寄存器组和组合逻辑构成的硬件时序电路。有限状态机的状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只可能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态。

有限状态机的下一个状态不但取决于各个输入值,还取决于当前所在状态。这里指的是米里Mealy型有限状态机,而莫尔Moore型有限状态机的下一个状态只决于当前状态。

Verilog HDL中可以用许多种方法来描述有限状态机,最常用的方法是用always语句和case语句。如图4.1所示的状态转移图表示了一个有限状态机,例4.1的程序就是该有限状态机的多种Verilog HDL模型之一。

图4.1的状态转移图表示了一个四状态的有限状态机。它的同步时钟是Clock,输入信号是A和Reset,输出信号是F和G。

状态的转移只能在同步时钟(Clock)的上升沿时发生,往哪个状态的转移则取决于目前所在的状态和输入的信号(Reset和A)。下面的例子是该有限状态机的Verilog HDL模型之一。

例4.1:Gray码有限状态机模型1。

module  fsm (Clock, Reset, A,  F, G);           //模块声明
      input Clock, Reset,
A;
      output F,G;
      reg F,G;
      reg [1:0] state ;

parameter                                      //状态声明
            Idle  =
2’b00,  Start = 2’b01,
            Stop = 2’b10, Clear = 2’b11;

always @(posedge Clock)
            if (!Reset) begin
                
state <= Idle;  F<=0; G<=0;      //默认状态
           
end
            else case (state)
                  idle: 
begin                       //Idle状态
                        if (A) 
begin
                              state <=
Start;
                              G<=0;
                       
end
                        elsestate <= idle;
                 
end
                  start:                             
//Start状态
                       if (!A)  state <=
Stop;
                       else    state <= start;
                 
Stop:  begin                       //Stop状态
                       if (A)
begin
                             state <=
Clear;
                             F <= 1;
                      
end
                       else   state <= Stop;
                      
end
                  Clear: begin                       
//Clear状态
                        if (!A) 
begin 
                             state
<=Idle;
                             F <=0; G
<=1;
                        end
                  else   state <=
Clear;
                  end
            endcase
endmodule

也可以用下面的Verilog
HDL模型来表示同一个有限状态。

例4.2:独热码有限状态和模型。

module 
fsm (Clock, Reset, A,  F, G);         //模块声明
      input Clock, Reset,
A;
      output F,G;
      reg F,G;
      reg [3:0] state ;

parameter                                    //状态声明
           Idle     =
4’b1000, 
           Start    = 4’b0100, 
           Stop     =
4’b0010,
           Clear    = 4’b0001;

always @(posedge clock)
           if (!Reset) begin
                
state <= Idle;  F<=0; G<=0;    //默认状态
           end
          
else case (state)
                 Idle:  begin                     
//Idel状态
                      if (A)  begin
                           
state <= Start;
                           
G<=0;
                            end
                      else state
<= Idle;
                 end
                
Start:                             //Start状态
                       if (!A) 
state <= Stop;
                             else  state <=
Start;
                 Stop:  begin                     
//Stop状态
                       if (A)
begin
                                  state <=
Clear;
                                  F <=
1;
                             end
                       else  state
<= Stop;
                 end
                 Clear:
begin                      //Clear状态
                       if (!A) 
begin 
                             state
<=Idle;
                             F<=0; 
G<=1;
                       end
                       else   state
<= Clear;
                 end
                 default:  state
<=Idle;         //默认状态
            endcase
endmodule

例4.2与例4.1的主要不同点是状态编码方式。例4.2采用了独热编码,而例4.1则采用Gray码,究竟采用哪一种编码好要看具体情况而定。

对于用FPGA实现的有限状态机建议采用独热码。因为虽然采用独热编码多用了两个触发器,但所用组合电路可省下许多,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。

采用了独热码后有了多余的状态,就有一些不可到达的状态,为此在CASE语句的最后需要增加default分支项,以确保多余状态能回到Idle状态。

另外还可以用另一种风格的Verilog HDL模型来表示同一个有限状态。在这个模型中,我们用always语句和连续赋值语句把状态机的触发器部分和组合逻辑部分分成两部分来描述,如下所示。

例4.3:有限状态机模型3

module  fsm (Clock, Reset, A,  F, G);               //模块声明
      input Clock, Reset, A;
      output F,G;
      reg [1:0] state ;
      wire [1:0] Nextstate;

parameter                                         //状态声明
           Idle  = 2’b00,  Start = 2’b01, 
           Stop = 2’b10,   Clear = 2’b11;

always @(posedge Clock)
           if (!Reset) begin
                 state <= Idle;                        //复位状态
           end
           else
                state <= Nextstate;                   //状态转换

assign Nextstate =                              //状态变换条件
           (state == Idle ) ?   (A ?  Start : Idle):
           (state==Start ) ?   (!A ?  Stop  : Start ):
           (state== Stop ) ?   (A ?  Clear : Stop ):
           (state== Clear) ?   (!A ?  Idle   : Clear) : Idle;

assign   F  = (( state == Stop) && A );       //状态输出
      assign   G =  (( state == Clear) && (!A || !Reset)) //状态输出
endmodule

下面是第4种风格的Verilog HDL模型来表示同一个有限状态。在这个模型中,我们分别用沿触发的always语句和电平敏感的always语句把状态机的触发器部分和组合逻辑部分分成两部分来描述。

例4.4:有限状态机模型4。

module  fsm (Clock, Reset, A,  F, G);           //模块声明
      input Clock, Reset, A;
      output F,G;
      reg [1:0] state, Nextstate;

parameter                                      //状态声明
           Idle  = 2’b00,  Start = 2’b01, 
           Stop = 2’b10, Clear = 2’b11;

always @(posedge Clock)
           if (!Reset) begin
                 state <= Idle;                   //默认状态
           end
           else
                 state <= Nextstate;             //状态转换

always @( state or A ) begin
           F=0;
           G=0;
           if (state == Idle) begin             //处于Idel状态时,对A判断
                 if (A)
                      Nextstate  =  Start;        //Start状态
                 else
                      Nextstate  =  Idle;         //保持Idel状态
                 G=1;
           end
           else if (state == Start)             //处于Start状态时,对!A判断
                 if (!A)
                      Nextstate  =  Stop;         //Stop状态
                 else
                      Nextstate  =  Start;        //保持Start状态
           else if (state == Stop)               //处于Stop状态时,对A判断
                 if (A)
                      Nextstate  =  Clear;        //Clear状态
                 else
                      Nextstate  =  Stop;         //保持Stop状态
           else if (state == Clear) begin      //处于Clear状态时,对!A判断
                 if (!A)
                      Nextstate  =  Idle;         //Idel状态
                 else
                      Nextstate  =  Clear;        //保持Clear状态
                 F=1;
                 end
           else
                 Nextstate= Idle;                 //默认状态
      End
endmodule

上面4个例子是同一个状态机的4种不同的Verilog HDL模型,它们都是可综合的,在设计复杂程度不同的状态机时有它们各自的优势。如用不同的综合器对这4个例子进行综合,综合出的逻辑电路可能会有些不同,但逻辑功能是相同的。

下面讲解有限状态机设计的一般步骤。

(1)逻辑抽象,得出状态转换图。
就是把给出的一个实际逻辑关系表示为时序逻辑函数,可以用状态转换表来描述,也可以用状态转换图来描述,这就需要完成以下任务。

① 分析给定的逻辑问题,确定输入变量、输出变量以及电路的状态数。通常是取原因(或条件)作为输入变量,取结果作为输出变量。
② 定义输入、输出逻辑状态的含意,并将电路状态顺序编号。
③ 按照要求列出电路的状态转换表或画出状态转换图。
这样,就把给定的逻辑问题抽象到一个时序逻辑函数了。

(2)状态化简。
如果在状态转换图中出现这样两个状态,它们在相同的输入下转换到同一状态去,并得到一样的输出,则称它们为等价状态。显然等价状态是重复的,可以合并为一个。电路的状态数越少,存储电路也就越简单。状态化简的目的就在于将等价状态尽可能地合并,以得到最简的状态转换图。

(3)状态分配。
状态分配又称状态编码。通常有很多编码方法,编码方案选择得当,设计的电路可以很简单。反之,若编码方案选得不好,则设计的电路就会复杂许多。

实际设计时,需综合考虑电路复杂度与电路性能之间的折衷。在触发器资源丰富的FPGA或ASIC设计中,采用独热编码(one-hot-coding)既可以使电路性能得到保证,又可充分利用其触发器数量多的优势。

(4)选定触发器的类型并求出状态方程、驱动方程和输出方程。

(5)按照方程得出逻辑图。

用Verilog HDL来描述有限状态机,可以充分发挥硬件描述语言的抽象建模能力,使用always块语句和case(if)等条件语句及赋值语句即可方便实现。具体的逻辑化简及逻辑电路到触发器映射均可由计算机自动完成。上述设计步骤中的第(2)、(4)、(5)步不再需要很多的人为干预,使电路设计工作得到简化,效率也有很大的提高。

4.4.2  FSM设计实例

例4.5:宇宙飞船控制器的状态机。

module  statmch1(   launch_shuttle, land_shuttle, start_countdown,
                       start_trip_meter, clk, all_systems_go,
                       just_launched, is_landed, cnt, abort_mission
                       );
      // I/O说明
      output launch_shuttle, land_shuttle, start_countdown,start_trip_meter;
      input  clk, just_launched, is_landed, abort_mission,all_systems_go;
      input  [3:0]  cnt;
      reg    launch_shuttle, land_shuttle, start_countdown,start_trip_meter;
      reg  [4:0]  present_state,  next_state;
      //设置独热码状态的参数
      parameter  HOLD=5‘h1, SEQUENCE=5‘h2, LAUNCH=5‘h4;
      parameter  ON_MISSION=5‘h8, LAND=5‘h10;

always @(negedge clk or posedge abort_mission) begin
            //把输出设置成某个缺省值,在下面的case语句中就不必再设置输出的缺省值
            {launch_shuttle, land_shuttle, start_trip_meter, start_countdown} = 4‘b0;
            //检查异步reset的值,即abort_mission的值
            if(abort_mission)
                 next_state = LAND;
            else begin
                 //如果abort_mission为零,把next_state赋值为present_state
                 next_state = present_state;
                 //根据 present_state 和输入信号,设置 next_state和输出output
                 case ( present_state )
                      HOLD:                               //HOLD状态
                            if(all_systems_go) begin
                                 next_state = SEQUENCE;
                                 start_countdown = 1;
                            end
                      SEQUENCE:                          //SEQUENCE状态
                            if(cnt==0)
                                 next_state = LAUNCH;
                      LAUNCH: begin                     //LAUNCH状态
                            next_state = ON_MISSION;
                            launch_shuttle = 1;
                            end
                      ON_MISSION:                       //ON_MISSION状态
                            if(just_launched)
                                 start_trip_meter = 1; //取消使命前,一直留在使命状态
                      LAND:                              //LAND状态
                           if(is_landed)
                                 next_state = HOLD;
                           else land_shuttle = 1;
                      default:  next_state = ‘bx;//把缺省状态设置为‘bx(无关)或某种已
                                                    //知状态,使其在做仿真时,在复位前就
                                                    //与实际情况相一致
                 endcase
           end                   // if-else语句结束
           present_state = next_state;        //把当前状态变量设置为下一状态,
                                                   //待下一有效时钟沿来到时,当前状
                                                    //态变量已设置了正确的状态值
     end                         //always块结束
endmodule

4.4.3  设计可综合状态机的指导原则
(1)独热码。
因为大多数FPGA内部的触发器数目相当多,又加上独热码状态机(one hot state machine)的译码逻辑最为简单,所以在设计采用FPGA实现的状态机时,往往采用独热码状态机(即每个状态只有一个寄存器置位的状态机)。

(2)case语句。
建议采用case、casex或casez语句来建立状态机的模型。因为这些语句表达清晰明了,可以方便地从当前状态分支转向下一个状态并设置输出。

采用这些语句设计状态机时,不要忘记写上case语句的最后一个分支default,并将状态变量设为‘bx。这就等于告知综合器:case语句已经指定了所有的状态。这样综合器就可以删除不需要的译码电路,使生成的电路简洁,并与设计要求一致。

如果将缺省状态设置为某一确定的状态(例如:设置default:state = state1),行不行呢?”这样做有一个问题需要注意:因为尽管综合器产生的逻辑和设置“default:state=‘bx”时相同,但是状态机的Verilog HDL模型综合前和综合后的仿真结果会不一致。

为什么会是这样呢?因为启动仿真器时,状态机所有的输入都不确定,因此立即进入default状态。如果通过设置将状态变量设为state1,但是实际硬件电路的状态机在通电之后,进入的状态是不确定的,很可能不是state1的状态,这样就会产生不必要的冲突。

因此,还是设置“default:state=‘bx”与实际硬件电路相一致。但在有多余状态的情况下还是应将缺省状态设置为某一确定的有效状态,因为这样做能使状态机若偶然进入多余状态后仍能在下一时钟跳变沿时返回正常工作状态,否则会引起死锁。

(3)复位。
状态机应该有一个异步或同步复位端,以便在通电时将硬件电路复位到有效状态,也可以在操作中将硬件电路复位(大多数FPGA结构都允许使用异步复位端)。

(4)惟一触发。
目前大多数综合器往往不支持在一个always块中由多个事件触发的状态机(即隐含状态机,implicit state machines)。因此为了能综合出有效的电路,用Verilog HDL描述的状态机应明确地由惟一时钟触发。

(5)异步状态机。
异步状态机是没有确定时钟的状态机,它的状态转移不是由惟一的时钟跳变沿所触发。目前大多数综合器不能综合采用Verilog HDL描述的异步状态机。

因此应尽量不要使用综合工具来设计异步状态机。因为目前大多数综合工具在对异步状态机进行逻辑优化时会胡乱地简化逻辑,使综合后的异步状态机不能正常工作。如果一定要设计异步状态机,建议采用电路图输入的方法,而不要用Verilog HDL输入的方法。

(6)状态赋值。
Verilog HDL中,状态必须明确赋值,通常使用参数parameters或宏定义define语句加上赋值语句来实现。

使用参数parameters语句赋状态值如下所示:

parameter  state1 = 2 ‘h1,  state2 = 2 ‘h2;
...
current_state = state2;           //把current state设置成 2‘h2
...

使用宏定义define语句赋状态值如下所示:

‘define state1  2 ‘h1
‘define state2  2 ‘h2
...
current_state = ‘state2;           //把current state设置成 2 ‘h2

时间: 2024-08-28 23:32:08

Verilog HDL设计进阶:有限状态机的设计原理及其代码风格_zt的相关文章

基于Verilog HDL整数乘法器设计与仿真验证

基于Verilog HDL整数乘法器设计与仿真验证 1.预备知识 整数分为短整数,中整数,长整数,本文只涉及到短整数.短整数:占用一个字节空间,8位,其中最高位为符号位(最高位为1表示为负数,最高位为0表示为正数),取值范围为-127~127. 负数的表示方法为正值的求反又加1.例如: 8’b0000_0100; //表示值:4,正值求反为:8’b1111_1011:再加1表示为:8’b1111_1100,这样便得到了-4的表示方法为:8’b1111_1100. 同理,负值变成正值的方法为:负值

第三章 Verilog HDL的模块化设计和描述方法

一.模块申明 verilog HDL设计以模块为基础,以关键字module开始,以endmodule结束,其格式如下: 二.模块例化 对于模块例化(实例调用)的时候,需要将两个端口的信号连接起来,在Verilog HDL中有两种方法进行端口连接:顺序连接和名称连接.这两种连接方式只可单独使用,不可混合使用. 1.顺序连接 需要连接到模块实例的信号必须和模块声明时的目标端口列表中的位置保持一致. 2.名称连接法 原文地址:https://www.cnblogs.com/guojun-junguo/

8421BCD转余3码Verilog HDL的设计(2)

接着上节8421BCD转余3码Verilog HDL的设计(1),分析另一条路径A-C分支 (1)在C状态,t1时刻Bin输入的值可能为0或者1:当bin输入0时,进入F状态:当bin输入1时,进入G状态,比特流Bin二进制为t3t2t1t0的可能性如下: C状态(t1时刻,Bin=0),Bout=0 C状态(t1时刻,Bin=1),Bout=1 t3t2t1t0 T3T2T1T0 下一状态为F状态 t3t2t1t0 T3T2T1T0 下一状态为G状态 0001 0100 0011 0110 0

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

0.前言 在上篇文章<Spring设计思想>AOP设计基本原理中阐述了Spring AOP 的基本原理以及基本机制,本文将深入源码,详细阐述整个Spring AOP实现的整个过程. 读完本文,你将了解到: 1.Spring内部创建代理对象的过程 2.Spring AOP的核心---ProxyFactoryBean 3.基于JDK面向接口的动态代理JdkDynamicAopProxy生成代理对象 4.基于Cglib子类继承方式的动态代理CglibAopProxy生成代理对象 5.各种Advice

分布式进阶(十七)分布式设计介绍

分布式设计介绍 前言 分布式设计与开发在IDF05(Intel Developer Forum 2005)上,Intel首席执行官Craig Barrett就取消4GHz芯片计划一事,半开玩笑当众单膝下跪致歉,给广大软件开发者一个明显的信号,单纯依靠垂直提升硬件性能来提高系统性能的时代已结束,分布式开发的时代实际上早已悄悄地成为了时代的主流,吵得很热的云计算实际上只是包装在分布式之外的商业概念,很多开发者(包括我)都想加入研究云计算这个潮流,在google上通过"云计算"这个关键词来查

paip.自适应网页设计 跟 响应式 设计的区别跟原理and实践总结

建立map的方式(其实用的是json实现方式) var a = {}; a["key1"] = "value1"; a["key2"] = "value2"; 既然是个map就有检索某个键是否存在的方法,这样写 if ("key1" in a) { // something } else { // something else } 简单的一句话声明map里面的key和value的方式: var a = {'

[Verilog]任意整数(奇数,整数)分频器设计, 50%占空比

module div_clk(clk_in, divisor, clk_out); input clk_in; input divisor; output clk_out; reg clk_out = 0; wire clk_in; reg [7 : 0] count = 0; wire [7 : 0] divisor; wire odd; assign odd = divisor & 1; always @(clk_in) begin if (count == 0 && clk_

走向DBA[MSSQL篇] 针对大表 设计高效的存储过程【原理篇】 附最差性能sql语句进化过程客串

原文:走向DBA[MSSQL篇] 针对大表 设计高效的存储过程[原理篇] 附最差性能sql语句进化过程客串 测试的结果在此处 本篇详解一下原理 设计背景 由于历史原因,线上库环境数据量及其庞大,很多千万级以上甚至过亿的表.目标是让N张互相关联的表 按照一张源表为基表,数据搬移归档 这里我们举例N为50 每张表数据5000W 最差性能sql进化客串 2表KeyName 字段意义 名称等相同 从bug01 表中取出前500条不在bug02 表中的数据 最差性能: SELECT TOP 500 a.K

流水线cpu —Verilog HDL

一.准备工作 先看看书(<计算机原理与设计 Verilog HDL版>),搞懂一点原理.然后照着书上的代码写一写(用8.4的就可以了,不用8.6的). 注意mux2x32,mux4,cla32等可以用单周期的mux,alu. (cla32就是个加法器,) 然后dffe32在书上前几章也有. pipeimem即为im指令存储器,可以套用单周期的IM. pipemem是数据存储器,可以套用单周期的dm regfile 可以套用单周期的RF. alu可以完全套用单周期的alu.pipecu中的alu