微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > FPGA Verilog HDL 设计实例系列连载--------有限状态机设计

FPGA Verilog HDL 设计实例系列连载--------有限状态机设计

时间:10-02 整理:3721RD 点击:

数字系统有两大类有限状态机(Finite State Machine,FSM):Moore状态机和Mealy状态机。

Moore状态机

  其最大特点是输出只由当前状态确定,与输入无关。Moore状态机的状态图中的每一个状态都包含一个输出信号。这是一个典型的Moore状态机的状态跳转图,x、y、z是输入,a、b、c是输出。



Mealy状态机

  它的输出不仅与当前状态有关系,而且与它的输入也有关系,因而在状态图中每条转移边需要包含输入和输出的信息。



状态编码

  数字逻辑系统状态机设计中常见的编码方式有:二进制码(Binary码)、格雷码(Gray码)、独热码(One-hot码)以及二一十进制码(BCD码)。

  格雷码的特点:相邻的两个码组之间仅有一位不同。

普通二进制码与格雷码之间可以相互转换。

  二进制码转换为格雷码:从最右边一位起,一次与左边一位“异或”,作为对应格雷码该位的值,最左边的一位不变(相当于最左边是0)。

  格雷码转换为二进制码:从左边第二位起,将每一位与左边一位解码后的值“异或”,作为该解码后的值(最左边的一位依然不变)。

  独热码又分为独热1码和独热0码,是一种特殊的二进制编码方式。当任何一种状态有且仅有一个1时,就是独热1码,相反任何一种状态有且仅有一个0时,就是独热0码。

状态机的描述

  状态机有三种描述方式:一段式状态机、两段式状态机、三段式状态机。下面就用一个小例子来看看三种方式是如何实现的。

  

(各种图片,各种坑爹啊 - -!)


一段式状态机

  当把整个状态机卸载一个always模块中,并且这个模块既包含状态转移,又含有组合逻辑输入/输出时,称为一段式状态机。不推荐采用这种状态机,因为从代码风格方面来讲,一般都会要求把组合逻辑和时序逻辑分开;从代码维护和升级来说,组合逻辑和书序逻辑混合在一起不利于代码维护和修改,也不利于约束。

  1. //一段式状态机来实现:在异步复位信号的控制下,一段式状态机进入IDLE
  2. //状态,q_sig4被复位,一旦sig1或者sig2有效,状态机进入WAIT状态,如果
  3. //sig1和sig2同时有效,那么状态机进入DONE状态,
  4. //如果sig4还有效,那么q_sig4置位,同时状态机进入IDLE状态。

  5. module one_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4,q_sm_state);
  6. //数据声明部分
  7. input clk,reset,sig1,sig2,sig3;

  8. output reg       q_sig4;
  9. output reg [1:0] q_sm_state;

  10. //参数声明
  11. parameter  IDLE       = 2'b00;
  12. parameter  WAIT       = 2'b01;
  13. parameter  DONE       = 2'b10;

  14. //状态跳转逻辑程序设计
  15. always @(posedge clk or posedge reset)
  16.    begin
  17.        if(reset)
  18.        begin
  19.            q_sig4     <= 0;
  20.            q_sm_state <= IDLE;
  21.        end
  22.      else
  23.          begin
  24.              case(q_sm_state)
  25.                    IDLE: begin
  26.                               if(sig1 || sig2)
  27.                                    begin
  28.                                        q_sm_state <= WAIT;
  29.                                        q_sig4 <= 1'b0;
  30.                                    end
  31.                                   else
  32.                                       begin
  33.                                           q_sm_state <= IDLE;
  34.                                           q_sig4 <= 1'b0;
  35.                                     end
  36.                            end
  37.                    WAIT: begin
  38.                              if(sig2 && sig3)
  39.                                  begin
  40.                                      q_sm_state <= DONE;
  41.                                      q_sig4     <= 1'b0;
  42.                                end
  43.                              else
  44.                                  begin
  45.                                      q_sm_state <= WAIT;
  46.                                      q_sig4     <= 1'b0;
  47.                                end
  48.                           end      
  49.                                     
  50.                    DONE:begin
  51.                             if(sig3)
  52.                                 begin
  53.                                     q_sm_state <= IDLE;
  54.                                     q_sig4     <= 1'b1;
  55.                                 end
  56.                             else
  57.                                 begin
  58.                                     q_sm_state <= DONE;
  59.                                     q_sig4     <= 1'b0;
  60.                                 end
  61.                            end
  62.                     
  63.                  default: begin
  64.                               q_sm_state <= IDLE;
  65.                               q_sig4     <= 0;
  66.                             end
  67.            endcase   
  68.      end
  69.    end
  70. endmodule

复制代码

两段式状态机

  所谓的两段式状态机就是采用一个always语句来实现时序逻辑,另外一个always语句来实现组合逻辑,提高了代码的可读性,易于维护。不同于一段式状态机的是,它需要定义两个状态----现态和次态,然后通过现态和次态的转换来实现时序逻辑。

  1. //本例主要采用两段式状态机:在异步复位信号的控制下,一段式状态机进入IDLE
  2. //状态,q_sig4被复位,一旦sig1或者sig2有效,状态机进入WAIT状态,如果sig1和sig2同时有效,那么
  3. //状态机进入DONE状态,如果sig4还有效,那么q_sig4置位,同时状态机进入IDLE状态。

  4. module two_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4);
  5. //数据声明部分
  6. input clk,reset,sig1,sig2,sig3;

  7. output reg       q_sig4;

  8. reg [1:0]    current_state, next_state;

  9. //参数声明
  10. parameter  IDLE       = 2'b00;
  11. parameter  WAIT       = 2'b01;
  12. parameter  DONE       = 2'b10;

  13. //状态跳转程序设计
  14. always @(posedge clk or posedge reset)
  15.   if(reset)
  16.       current_state <= IDLE;
  17.   else
  18.       current_state <= next_state;
  19.       
  20. //状态逻辑输出
  21. always @(current_state or sig1 or sig2 or sig3)
  22.    begin
  23.        case(current_state)
  24.        IDLE: begin
  25.                               if(sig1 || sig2)
  26.                                    begin
  27.                                        next_state = WAIT;
  28.                                        q_sig4    = 1'b0;
  29.                                    end
  30.                                   else
  31.                                       begin
  32.                                           next_state = IDLE;
  33.                                           q_sig4     = 1'b0;
  34.                                     end
  35.                            end
  36.                    WAIT: begin
  37.                              if(sig2 && sig3)
  38.                                  begin
  39.                                      next_state = DONE;
  40.                                      q_sig4     = 1'b0;
  41.                                end
  42.                              else
  43.                                  begin
  44.                                      next_state = WAIT;
  45.                                      q_sig4     = 1'b0;
  46.                                end
  47.                           end      
  48.                                     
  49.                    DONE:begin
  50.                             if(sig3)
  51.                                 begin
  52.                                     next_state = IDLE;
  53.                                     q_sig4     = 1'b1;
  54.                                 end
  55.                             else
  56.                                 begin
  57.                                     next_state = DONE;
  58.                                     q_sig4     = 1'b0;
  59.                                 end
  60.                            end
  61.                     
  62.                  default: begin
  63.                               next_state = IDLE;
  64.                               q_sig4     = 0;
  65.                             end
  66.            endcase   
  67.      
  68.    end
  69. endmodule

复制代码

三段式状态机

  三段式状态机与两段式状态机的区别:两段式直接采用组合逻辑输出,而三段式则通过在组合逻辑后再增加一级寄存器来实现时序逻辑输出。这样做的好处是可以有效地滤去租个逻辑输出的毛刺,同时可以有效地进行时序计算与约束,另外对于总线形式的输出信号来说,容易使总线数据对其,从而减小总线数据间的偏移,减小接收端数据采样出错的频率。

  三段式状态机的基本格式是:第一个always语句实现同步状态跳转;第二个always语句实现组合逻辑;第三个always语句实现同步输出。

  1. //本例主要采用三段式状态机:在异步复位信号的控制下,一段式状态机进入IDLE
  2. //状态,q_sig4被复位,一旦sig1或者sig2有效,状态机进入WAIT状态,如果sig1和sig2同时有效,那么
  3. //状态机进入DONE状态,如果sig4还有效,那么q_sig4置位,同时状态机进入IDLE状态。

  4. module three_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4);
  5. //数据声明部分
  6. input clk,reset,sig1,sig2,sig3;

  7. output reg       q_sig4;

  8. reg [1:0]    current_state, next_state;

  9. //参数声明
  10. parameter  IDLE       = 2'b00;
  11. parameter  WAIT       = 2'b01;
  12. parameter  DONE       = 2'b10;

  13. //状态跳转程序设计
  14. always @(posedge clk or posedge reset)
  15.   if(reset)
  16.       current_state <= IDLE;
  17.   else
  18.       current_state <= next_state;
  19.       
  20. //状态跳转输出
  21. always @(current_state or sig1 or sig2 or sig3)
  22.    begin
  23.        case(current_state)
  24.        IDLE: begin
  25.                               if(sig1 || sig2)
  26.                                    begin
  27.                                        next_state = WAIT;                                      
  28.                                    end
  29.                                   else
  30.                                       begin
  31.                                           next_state = IDLE;                                         
  32.                                     end
  33.                            end
  34.                    WAIT: begin
  35.                              if(sig2 && sig3)
  36.                                  begin
  37.                                      next_state = DONE;                                    
  38.                                end
  39.                              else
  40.                                  begin
  41.                                      next_state = WAIT;                                    
  42.                                end
  43.                           end      
  44.                                     
  45.                    DONE:begin
  46.                             if(sig3)
  47.                                 begin
  48.                                     next_state = IDLE;                                   
  49.                                 end
  50.                             else
  51.                                 begin
  52.                                     next_state = DONE;                                   
  53.                                 end
  54.                            end
  55.                     
  56.                  default: begin
  57.                               next_state = IDLE;                             
  58.                             end
  59.            endcase      
  60.    end
  61.    
  62.    //逻辑输出
  63.    always @(posedge clk or posedge reset)
  64.      if(reset)
  65.          q_sig4 <= 1'b0;
  66.      else
  67.          begin
  68.              case(next_state)
  69.                  IDLE,
  70.                  WAIT: q_sig4 <= 1'b0;
  71.                  DONE: q_sig4 <= 1'b1;
  72.                  default: q_sig4 <= 1'b0;
  73.            endcase
  74.          end
  75.          
  76. endmodule

复制代码


很好

超牛

多谢分享。

很强大的程序设计啊

高手

看一下

看看有帮助

小编写的很好,收益很多,谢谢分享

好,正要找的呢,好

我想问一下,为什么用异步复位得到的状态图是不对的?

还是不太明白一段和二段的区别,二段不过多加了个寄存器,而且二段说是组合逻辑和时序逻辑分开,组合逻辑是指状态逻辑输出那部分程序吗?能不能用硬件图来给个详细的解释

恩!@                  

好好参考一下

这么好的资料,我要好好学学

匪巢                  

顶                                       

小编辛苦了。

顶顶顶顶顶顶

特别感谢小编的分享  要看看

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top