当前位置: 首页 > news >正文

[Verilog]有限状态机设计举例

有限状态机设计举例

       摘要:有限状态机(FSM)是许多数字系统中用来控制系统和数据流路径行为的时序电路。FSM的实例包括控制单元时序。 本实验介绍了两种类型的FSM(MealyMoore)的概念,以及开发此类状态机的建模方式。 请参阅Vivado教程,了解如何使用Vivado工具创建项目和验证数字电路。

一、实验目标

   在本次实验中,你将会学到:

  • 对 Mealy FSMs 建模
  • 对 Moore FSMs 建模

    1.1 Mealy FSM(米利型有限状态机)

           有限状态机(FSM)或称简单状态机用于设计计算机程序和时序逻辑电路。它被设想为抽象机器,可以处于有限数量的用户定义状态之一。机器一次只能处于一种状态; 它在任何给定时间所处的状态称为当前状态。 当由触发事件或条件启动时,它可以从一种状态改变为另一种状态; 这称为过渡。特定FSM由其状态列表和每个转换的触发条件定义。
           在现代社会中的许多设备中可以观察到状态机的踪影,这些设备根据发生的事件序列执行预定的动作序列。 简单的例子是自动售货机,当存放硬币的金额达到商品价格时分配产品;电梯在把乘客送达楼上后才会下降;交通灯按一定的时间改变信号来控制车流;以及需要输入一串正确的数字才能打开的组合锁。
           状态机使用两种基本类型建模–Mealy和Moore。 在Mealy机器中,输出取决于当前状态和当前输入。在Moore机器中,输出仅取决于当前状态。
           Mealy型状态机的一般模型由组合过程电路状态寄存器组成,组合过程电路生成输出和下一个状态,状态寄存器保存当前状态,如下图所示。状态寄存器通常建模为D触发器。状态寄存器必须对时钟边缘敏感。其他块可以使用always过程块或always过程块和dataflow建模语句的混合来建模;always过程块必须对所有输入敏感,并且必须为每个分支定义所有输出,以便将其建模为组合块。两段式Mealy机器可以表示为

  • 下面是奇偶校验校验机的状态图和相关模型:

module mealy_2processes(input clk, input reset, input x, 
  output reg parity
); 

  reg state, nextstate;
  parameter S0 = 0, S1 = 1;

  always @(posedge clk or posedge reset) begin	// always block to update state 
    if (!reset)
      state <= S0;
    else
      state <= nextstate;
  end

  always @(state or x) begin   // always block to compute both output & next_state
    parity = 1'b0; 
    case(state)
      S0: if(x) begin
            parity = 1; 
            nextstate = S1;
          end else begin
            nextstate = S0;
          end
      S1: if(x) begin
            nextstate = S0;
          end
          else begin
            parity = 1; 
            nextstate = S1;
          end
      default : nextstate = S0; 

    endcase

  end

endmodule
  • 三段式Mealy机器的图示及其建模如下:

module mealy_3processes(input clk, input reset, input x, 
  output reg parity
); 

  reg state, nextstate;
  parameter S0 = 0, S1 = 1;

  always @(posedge clk or posedge reset)  // always block to update state 
    if (reset)
      state <= S0;
    else
      state <= nextstate;

  always @(state or x)	begin             // always block to compute output 
    parity = 1'b0;
    case(state)
      S0 : if(x)  parity = 1; 
           else   parity = 0; 
      S1 : if(!x) parity = 1;
           elsle  parity = 0;
    endcase 
  end

  always @(state or x) begin             // always block to compute nextstate 
    nextstate = S0; 
    case(state)
      S0: if(x)  nextstate = S1; 
          else   nextstate = S0; 
      S1: if(!x) nextstate = S1; 
          else   nextstate = S0; 
    endcase
  end 

endmodule

       状态分配可以使用独热码(one – hot code),二进制编码,格雷码以及其他编码。通常,综合工具将确定状态分配的编码,但用户也可以通过更改综合属性来强制特定编码,如下所示。状态分配编码将对状态寄存器中使用的位数产生影响;独热编码使用最多的位数,但解码非常快,二进制编码使用最少的位数,但解码较长。

二、使用三段式Mealy状态机的实现一个序列检测器

 2.1 实验要求

       Mealy状态机有一个输入(ain)和一个输出(yout)。 当且仅当接收到的1的总数可被3整除时,输出为1(提示:0也算被3整除,但是,在复位周期中不把计数器归为0,复位信号过后把计数器归0——参考模拟波形时间= 200)。

       设计一个testbench并通过behavioral simulation验证模型。 使用SW15作为时钟输入,SW0作为输入,BTNU按钮作为电路的复位输入,LED7:LED4上的1s计数和作为yout输出的LED0。 完成设计流程,生成比特流,并将其下载到Basys3或Nexys4 DDR板。验证功能。

 2.1 实验步骤

  1. 打开Vivado并创建一个空工程并命名为lab10_1。

  2. 创建并添加使用SW15作为时钟输入,SW0作为输入,BTNU按钮作为电路的复位输入,LED7:LED4上的1s计数和作为yout输出的LED0。

  3. 编写仿真文件来验证代码的正确

  4. 在工程中添加适当的管脚约束的XDC文件,并加入相关联的管脚,使用SW15作为时钟输入,SW0作为输入,BTNU按钮作为电路的复位输入,LED7:LED4上的1s计数和作为yout输出的LED0。

  5. 综合,实现设计。

  6. 生成比特流文件,下载到Nexys4开发板上,验证功能。

    参考代码和分析

    module lab10_1(input clk, input rst, input ain, 
      output reg [3:0]count, output reg yout
    );
    
      parameter s0=0, s1=1,s2=2; reg [1:0] state, nextstate; 
    
      always@(posedge clk or posedge rst) begin 
        if(rst) begin 
          state <= s0; 
          count <= 4’b0; 
        end else begin 
          state <= nextstate; 
          if(ain) count <= count + 1; 
        end 
      end
    
     always@(*) begin
       yout = 0;
       case(state)
         s0 : if(!ain) yout=1;         
         s2 : if(ain)  yout=1;         
       endcase
     end
    
     always@(*) begin
       case(state)
         s0:if(ain)
         nextstate=s1;
         else
         nextstate=s0;
         s1:if(ain)
         nextstate=s2;
         else
         nextstate=s1;
         s2:if(ain)
         nextstate=s0;
         else
          nextstate=s2;
        endcase
      end  
    endmodule
     
    
    

       米利型(Mealy)的输出是和当前状态以及输入都相关的,所以这里是这样的情况。但是如果是摩尔型的话输入只与当前状态相关,之后也会有介绍。

       摩尔型有限状态机(Moore FSM)型有限状态机的一般模型如下所示。 其输出由状态寄存器块生成。 使用当前输入和当前状态确定下一状态。 这里的状态寄存器也使用D触发器建模。 通常,Moore机器使用三个块来描述,其中一个块必须是顺序的,另外两个块可以使用always块或always和dataflow建模结构的组合来建模。    

  • 以下是使用Moore型有限状态机实现的奇偶校验器的状态图。与之关联模型如下所示。

module moore_3processes(input clk, input reset, input x, 
  output reg parity
); 

  reg state, nextstate;
  parameter S0=0, S1=1;

  always @(posedge clk or posedge reset) begin	// always block to update state 
    if (reset)
      state <= S0;
    else
      state <= nextstate;
  end

  always @(state) begin	// always block to compute output 
    case(state)
      S0 : parity = 0; 
      S1 : parity = 1;
      default : parity = S0;
    endcase
  end

  always @(state or x)	begin // always block to compute nextstate 
    nextstate = S0; 
    case(state)
      S0: if(x)  nextstate = S1; 
          else   nextstate = S0; 
      S1: if(!x) nextstate = S1;
          else   nextstate = S0;
      default : nextstate = S0;
    endcase
  end

endmodule

       在本例中,输出块很简单,可以使用dataflow建模构造进行建模。 可以使用以下代码代替always块。 您还需要将输出类型从reg更改为wire。

assign parity = (state == S0) ? 1'b0: 1'b1;
#使用三段式Moore状态机的实现一个序列检测器 
#实验要求Moore状态机有一个输入(ain)和一个输出(yout)。 
#当且仅当接收到的1的总数可被3整除时,输出为1(提示:0也算被3整除,但是,在复位周期中不把计数器归为0,复位信号过后把计数器归0——参考模拟波形时间= 200)。
#设计一个testbench并通过behavioral simulation验证模型。 使用SW15作为时钟输入,SW0作为输入,BTNU按钮作为电路的复位输入,
#LED7:LED4上的1s计数和作为yout输出的LED0。 
#完成设计流程,生成比特流,并将其下载到Basys3或Nexys4 DDR板。验证功能。

 2.2 实验步骤

  1. 打开Vivado并创建一个空工程并命名为lab10_2。

  2. 创建并添加使用SW15作为时钟输入,SW0作为输入,BTNU按钮作为电路的复位输入,LED7:LED4上的1s计数和作为yout输出的LED0。

  3. 编写仿真文件来验证代码的正确

  4. 在工程中添加适当的管脚约束的XDC文件,并加入相关联的管脚,使用SW15作为时钟输入,SW0作为输入,BTNU按钮作为电路的复位输入,LED7:LED4上的1s计数和作为yout输出的LED0。

  5. 综合,实现设计。

  • 生成比特流文件,下载到Nexys4开发板上,验证功能。

    参考代码和分析

    module lab10_2( input clk, input rst, input ain, 
      output reg [3:0] count, output reg yout
    );
    
      parameter s0=0, s1=1,s2=2; 
      reg [1:0] state, nextstate; 
    
      always@(posedge clk or posedge rst) begin 
        if(rst) begin 
          state <= s0; 
          count <= 4’b0; 
        end else begin 
          state <= nextstate; 
          if(ain) count <= count + 1; 
        end 
      end 
    
      always@(*) begin 
        case(state) 
          s0: yout = 1; 
          default : yout = 0; 
        endcase 
      end 
    
      always@(*) begin 
        case(state) 
          s0 : if(ain) nextstate = s1;   
               else    nextstate = s0; 
          s1 : if(ain) nextstate = s2; 
               else    nextstate = s1;  
          s2 : if(ain) nextstate = s0; 
               else    nextstate = s2; 
        endcase 
      end 
    
    endmodule

    摩尔型相较米利型输出的状态只与输入相关

三、扩展实验内容

 3.1 扩展实验1 使用三段式Moore状态机或者Mealy状态机实现一个序列检测器。

       Moore状态机有两个输入(ain [1:0])和一个输出(yout)。 除非出现以下输入序列之一,否则输出将从0开始并保持为常量值:

  1. 输入序列ain [1:0] = 01,00使输出变为0
  2. 输入序列ain [1:0] = 11,00使输出变为1
  3. 输入序列ain [1:0] = 10,00使输出切换。

    实验要求

    打开Vivado并创建一个空工程并命名为lab10_kuozhan1。设计一个testbench(类似于下面显示的波形)并通过behavioral simulation验证模型。 使用SW15作为时钟输入,SW1-SW0作为ain [1:0]输入,BTNU按钮作为电路的复位输入,LED0作为yout输出。 完成设计流程,生成比特流,并将其下载到Basys3或Nexys4 DDR板。 验证功能。
    仿真示意图如下:

 3.2 扩展实验2

    使用ROM设计一个特定的计数计数器(下面列出的计数序列)来开发一个Mealy状态机。

  • 实验要求

       打开Vivado并创建一个空工程并命名为lab10_kuozhan2。设计一个testbench并通过behavioral simulation验证模型。 使用SW15作为时钟输入,BTNU按钮作为电路的复位输入,LED2:LED0作为计数器的计数输出。 完成设计流程,生成比特流,并将其下载到Basys3或Nexys4 DDR板。 验证功能。
计数序列是: 000, 001, 011, 101, 111, 010 (repeat) 000, …

相关文章:

  • 机器学习和深度学习的关系
  • 一步一步学爬虫(4)数据存储之文本存储
  • 保姆教程系列二、Redis高可用(主从同步+哨兵模式)
  • 【C++进阶】类型转换
  • Java中序列化接口Serializable的serialVersionUID的作用
  • 【WSL】[02] windows subsytem linux 配置和使用
  • 机器学习之特征工程详解
  • 关于MongoDB处理统计图数据(按天,小时)
  • 小米裁员,我有话说
  • 【C++学习】vector的使用及模拟实现
  • SMC详解
  • 11.简单的CSS按钮悬停特效
  • 【数组】leetcode704.二分查找(C/C++/Java/Js)
  • CSDN竞赛19期题解
  • 过年不让放炮,我用Python实现了1000响大地红的特效
  • Apache Spark Streaming 使用实例
  • Date型的使用
  • Fundebug计费标准解释:事件数是如何定义的?
  • gops —— Go 程序诊断分析工具
  • in typeof instanceof ===这些运算符有什么作用
  • Js基础知识(四) - js运行原理与机制
  • Laravel 菜鸟晋级之路
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • Python十分钟制作属于你自己的个性logo
  • SpiderData 2019年2月16日 DApp数据排行榜
  • vue-loader 源码解析系列之 selector
  • 服务器之间,相同帐号,实现免密钥登录
  • 回顾 Swift 多平台移植进度 #2
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • FaaS 的简单实践
  • hi-nginx-1.3.4编译安装
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​MySQL主从复制一致性检测
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (4.10~4.16)
  • (C语言)二分查找 超详细
  • (二十三)Flask之高频面试点
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (已解决)什么是vue导航守卫
  • (译) 函数式 JS #1:简介
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • ./configure,make,make install的作用
  • .NET Core Web APi类库如何内嵌运行?
  • .NET gRPC 和RESTful简单对比
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .net和jar包windows服务部署
  • @EnableAsync和@Async开始异步任务支持
  • @RequestParam,@RequestBody和@PathVariable 区别
  • @serverendpoint注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • []我的函数库