草庐IT

11-verilog-有限状态机

ICER's BLOG 2023-03-28 原文

有限状态机

写RTL的时候,实现一个功能的时候有很多种方法

  1. 将系统划分为多个状态,状态之间有状态的转移,第一步,第二步,,,,形成有限状态机
  2. 流水线技术设计,从输入到输出有多个步骤
    有限状态机,状态是有限的,比如8个状态,16个状态等,在进行设计的时候,状态机的状态不要太多,状态超过10个,就会造成设计复杂度和验证复杂度都变高.

有限状态机分类

  1. Moore FSM
    输出只与当前的状态有关,与输入没有关系
  2. Mealy FSM
    输出不仅与当前的状态有关,还与输入有关

Moore FSM-设计自动售货机

分析输入输出信号

  • 自动售货机,输入的就是硬币,输出的是饮料和找零 (确定输入,输出)
  • 假设饮料只有一种价格2.5元,输入的零钱只有一元和五角(两种状态,用1bit表示),找零的情况只有两种0元和5角(用1bit表示)(确定输出输出的状态,用几位的信号表示)

定义接口

  • 状态机要存储一些状态,肯定会有一些寄存器,会有时钟和复位信号
  • 在设计一个模块的时候,最先确定输入输出的端口和位宽以及时序

定义时序

  • 输入的一元和五角不能同时为1(确定输入的约束)

内部实现--画出状态转移图

要存储当前已经存储了多少钱,初始状态时0,可以收到1元和5角

  • IDLE就是当前系统是空闲状态,没有收到任何的投币
  • 这是一个Moore类型的有限状态机,输出只与当前的状态有关
    Moore有限状态机电路特点
  1. 输入与当前的状态有关,所以需要一个寄存器存储当前的状态
  2. 寄存器存储的状态输入给组合逻辑之后,进行输出
  3. 输入与当前的状态值,经过组合逻辑之后,输入给寄存器
  4. 时序清晰,输入和输出,没有一条直接的组合逻辑路径;如果输入经过组合逻辑,没有经过寄存器,直接输出,这样的设计不好;因为不知道周围环境的组合逻辑的时序是多少

Code

module drink_status_moore(
  input clk,
  input reset,
  input half,
  input one,
  output out,
  output cout
);
  parameter [2:0] s0 = 3'b000,
                  s1 = 3'b001,
                  s2 = 3'b010,
                  s3 = 3'b011,
                  s4 = 3'b100,
                  s5 = 3'b101,
                  s6 = 3'b110;   //定义6个状态
  reg [2:0] curr_state;     //当前状态  CS
  reg [2:0] next_state;     //下一个状态 NS  reg定义的信号不一定是寄存器
  
  //第一段:声明一个寄存器,state transfer
  always @ (posedge clk ,negedge reset) begin
    if(~reset)
     curr_state <= s0;      //这里时钟来了之后,就寄存器传输,寄存器功耗比较大,需要给寄存器传输添加条件
    else
     curr_state <= #1 next_state; 
  end
  //第二段,根据条件写出中间状态转移
  always @ (curr_state,half,one) begin
    case(curr_state)
      s0:begin
         if(half)           next_state = s1;    //如果两个投币口,就会出现问题,一次投入可能为1.5元,所以要给输入添加约束
         else of(one)       next_state = s2;    //文件和文件之间需要进行一些约束
         else               next_state = S0;
         end
      s1:begin
         if(half)           next_state = s2;
         else of(one)       next_state = s3;
         else               next_state = S1;
         end
      s2:begin
         if(half)           next_state = s3;
         else of(one)       next_state = s4;
         else               next_state = S2;
         end
      s3:begin
         if(half)           next_state = s4;
         else of(one)       next_state = s5;
         else               next_state = S3;
         end
      s4:begin
         if(half)           next_state = s5;
         else of(one)       next_state = s6;
         else               next_state = S4;
         end
      s5:begin
                            next_state = s0;
         end
      s6:begin
                            next_state = s0;
         end
      default:              next_state = s0;
  end
  //第三段,写出输出
  assign out = (curr_state == s5) || (curr_State = s6) ? 1:0;
  assign cout = (curr_state == s6) ? 1:0;
endmodule

FSM 三段式的书写方式

mealy FSM-自动售货机

  • 相当于在当前状态,考虑之后输入的状态
  • 输入经过组合逻辑之后直接得到输出
module drink_status_moore(
  input clk,
  input reset,
  input half,
  input one,
  output out,
  output cout
);
  parameter [2:0] s0 = 3'b000,
                  s1 = 3'b001,
                  s2 = 3'b010,
                  s3 = 3'b011,
                  s4 = 3'b100;  //定义6个状态,变量名需要更加具有含义

  reg [2:0] curr_state;     //当前状态  CS
  reg [2:0] next_state;     //下一个状态 NS  reg定义的信号不一定是寄存器
  
  //第一段:声明一个寄存器,state transfer
  always @ (posedge clk ,negedge reset) begin
    if(~reset)
     curr_state <= s0;      //这里时钟来了之后,就寄存器传输,寄存器功耗比较大,需要给寄存器传输添加条件
    else
     curr_state <= #1 next_state; 
  end
  //第二段,根据条件写出中间状态转移
  always @ (*) begin
    case(curr_state)
      s0:begin
         if(half)           next_state = s1;    //如果两个投币口,就会出现问题,一次投入可能为1.5元,所以要给输入添加约束
         else of(one)       next_state = s2;    //文件和文件之间需要进行一些约束
         else               next_state = S0;
         end
      s1:begin
         if(half)           next_state = s2;
         else of(one)       next_state = s3;
         else               next_state = S1;
         end
      s2:begin
         if(half)           next_state = s3;
         else of(one)       next_state = s4;
         else               next_state = S2;
         end
      s3:begin
         if(half)           next_state = s4;
         else of(one)       next_state = s0;
         else               next_state = S3;
         end
      s4:begin
         if(half)           next_state = s0;
         else of(one)       next_state = s0;
         else               next_state = S4;
         end
      default:              next_state = s0;
    endcase
  end
  //第三段,写出输出
  assign out = ((curr_state == s4) & (half | one)) ? 1:
               ((curr_state == s3) & (one)) ? 1 : 0;
  assign cout = (curr_state == s4) & (one) ? 1 : 0;
endmodule

FSM有限状态机的设计步骤

  1. 接口定义(信号\位宽\约束)
  2. 状态定义和编码
  3. 状态转换图
  4. 按照三段式风格实现RTL代码
  5. 编写Testbench
  6. 使用QuestaSim进行编译和仿真
  7. 通过波形工具查看激励\状态信号和输出信号
  • Moore机输出只与当前状态有关
  • Mealy输出不仅与当前的状态有关,还与当前的输入有关

状态机的电路逻辑图

FSM要注意的问题

  1. case语句,要将所有的case列全
  2. 使用default语句还原状态;如果不写default,就需要写够所有可能

序列检测器

  • 输入就是1bit的x,输出的y也是1bity
  • 定义当前的状态,存储之前存储的序列是怎样的状态,初始为IDLE,中间状态可能会出现中间状态
  • IDLE在定义的时候,检测的序列是从1开始的,IDLE可以直接设计为初始值为1,中间状态出现01,10等不对的状态,可以取消掉


module seq(in,out,clk,reset,state);
  input in;
  input clk;
  input reset;
  output out;
  output [2:0] state;
  
  reg [2:0] curr_state;
  reg [2:0] next_state;
  
  parameter [2:0] s0 = 3'b000,
                  s1 = 3'b001,
                  s2 = 3'b010,
                  s3 = 3'b011,
                  s4 = 3'b100,
                  s5 = 3'b101,
                  s6 = 3'b110,
                  s7 = 3'b111;

  // 定义寄存器
  always @ (posedge clk , negedge reset)
  begin
    if(~reset)
      curr_state <= S0;
    else
      curr_state <= next_state;
  end
  
  // 写状态转移
  always @ (in,curr_state)
  begin
    case(curr_state)
      s0 : begin 
            if(in == 0)     next_state <= s0;
            else            next_state <= s1;              
           end
      s1 : begin 
            if(in == 0)     next_state <= s0;
            else            next_state <= s2;              
           end
      s2 : begin 
            if(in == 0)     next_state <= s0;
            else            next_state <= s3;              
           end
      s3 : begin 
            if(in == 0)     next_state <= s4;
            else            next_state <= s3;              
           end
      s4 : begin 
            if(in == 0)     next_state <= s5;
            else            next_state <= s1;              
           end
      s5 : begin 
            if(in == 0)     next_state <= s0;
            else            next_state <= s6;              
           end
      s6 : begin 
            if(in == 0)     next_state <= s7;
            else            next_state <= s2;              
           end
      s7 : begin 
            if(in == 0)     next_state <= s0;
            else            next_state <= s1;              
           end
      default:              next_state <= s0;
    endcase
  end
  
  // 输出
  assign out = (curr_state == s7) ? 1 : 0 ;
endmodule

有关11-verilog-有限状态机的更多相关文章

  1. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  2. ruby - 安装libv8(3.11.8.13)出错,Bundler无法继续 - 2

    运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin

  3. ruby - ri 有空文件 – Ubuntu 11.10, Ruby 1.9 - 2

    我正在运行Ubuntu11.10并像这样安装Ruby1.9:$sudoapt-getinstallruby1.9rubygems一切都运行良好,但ri似乎有空文档。ri告诉我文档是空的,我必须安装它们。我执行此操作是因为我读到它会有所帮助:$rdoc--all--ri现在,当我尝试打开任何文档时:$riArrayNothingknownaboutArray我搜索的其他所有内容都是一样的。 最佳答案 这个呢?apt-getinstallri1.8编辑或者试试这个:(非rvm)geminstallrdocrdoc-datardoc-da

  4. ruby-on-rails - 状态机、模型验证和 RSpec - 2

    这是我当前的类定义和规范:classEvent:not_starteddoevent:game_starteddotransition:not_started=>:in_progressendevent:game_endeddotransition:in_progress=>:finalendevent:game_postponeddotransition[:not_started,:in_progress]=>:postponedendstate:not_started,:in_progress,:postponeddovalidate:end_time_before_finalen

  5. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

  6. Verilog使用inout信号的方法 - 2

    目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法  实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电

  7. ruby-on-rails - 你为 Rails 推荐哪个状态机插件? - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion我正在为Rails3/ActiveRecord项目寻找一个相对简单的状态机插件。我做了一些研究并提出了以下插件:转换:https://github.com/qoobaa/transitions从旧的ActiveRecord状态机库中提取

  8. ruby-on-rails - Rails 2.3.11 DateTime BigDecimal 精度 - 2

    我目前有一个运行Ruby1.8.7和Rails2.3.2的RubyonRails项目我有一些从数据库中读取数据的单元测试,特别是两个连续项目的日期时间列,这两个项目应该相隔24小时。在一项测试中,我将项目2的日期时间设置为与项目1的日期时间相同。当我执行断言以确保两个值相等时,测试在rails2.3.2下工作正常。当我升级到rails2.3.11时,测试失败显示两次之间的差异将关闭并出现以下错误:expectedbutwas.这两个版本的rails中似乎存在浮点转换问题。如何解决float问题? 最佳答案 这也发生在我身上,我最终这

  9. ruby-on-rails - Ruby on Rails - 在 ':include =>' 上添加条件以加载有限数量的对象 - 2

    我有两个模型用户和事件。基数是一个用户有很多事件。当我查询数据库以提供所有用户及其相应事件时,它会返回正确的结果。示例语句:Users.find(:all,:include=>[:events])但是,我需要帮助的是根据条件为用户获取事件。我需要返回的每个用户只获取今天安排的事件(例如:CREATED_DATE=TODAY)。也就是说,我不希望所有事件都与用户关联。也就是说,我仍然需要在数据库中找到的所有用户,但对于今天没有安排事件的一些用户,他们不应该在HashMap中加载事件。有人可以帮我修改“Users.find(:all,:include=>[:events])”Rails语句

  10. ruby - AASM:将状态机定义与类定义分开 - 2

    假设我有这个类(直接取自aasm文档):classJobtruestate:runningstate:cleaningevent:rundotransitions:from=>:sleeping,:to=>:runningendevent:cleandotransitions:from=>:running,:to=>:cleaningendevent:sleepdotransitions:from=>[:running,:cleaning],:to=>:sleepingendendend我不太喜欢将状态机定义与类定义混合在一起的事实(当然,在实际项目中,我会向Job类添加更多方法)。我

随机推荐