risc-v中文社区

 找回密码
 立即注册
查看: 1078|回复: 1

[原创] chisel实现三状态的Mealy FSM

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-9-1 10:30:18 | 显示全部楼层 |阅读模式
前面介绍了Moore和Mealy FSM,当用于边沿检测的时候,比如说,val risingEdge = din & (!RegNext(din))
只要这么一句就可以实现上升沿检测,如果用前面所说的Mealy FSM,只用zero和one两个状态以Mealy进行检测
处理则一般不会这么处理,除非有多个状态才会用Mealy FSM处理比较合适。所以下面我将状态由二个变为三个,
然后再用Moore FSM处理上升沿检测,如下图:

图中,puls状态只有一个周期,然后要么返回zero状态要么返回one状态,然后再等待输入为0.
import chisel3._
import chisel3.util._
class RisingEdge3state extends Module {
  val io = IO(new Bundle {
    val din = Input(Bool())
    val risingEdge = Output(Bool())
  })
  //用util包中的Enum定义三个状态
  val zero :: puls :: one :: Nil = Enum(3)
  //状态寄存器
  val stateReg = RegInit(zero)
  //因为是Moore FSM,所以输出信号只与当前状态有关,与输入无关
  //在zero状态,如果din为1则状态变到plus
  //puls状态,如果din为1则状态变到one否则状态回到zero
  switch(stateReg) {//各个is是串行执行的吗????看verilog:if(){}else if(){} else if(){} else{}的关系
    is(zero) {
      when(io.din) {
        stateReg := puls  
      }
    }
    is(puls) {
      when(io.din) {
        stateReg := one
      } otherwise {
        //zero状态检测到了上升,但此周期ts之前居然又加到了0电平,说明是一个干扰
        //在用 din & !RegNext(din)这种语句检测时,只要检测到了1,下个周期ts之前加到0,输出还是不会变为1
        stateReg := zero
      }
    }
    is(one) {

      when(!io.din) { //如果电平不回到0,状态不需要改变回zero
        stateReg := zero
      }
    }
  }
  io.risingEdge := stateReg === puls  //输出是不是puls状态
}
从代码中可以看到寄存器所对应的D触发器比二状态的Mealy FSM或直接din & !RegNext(din)版本需求量多一倍,
当然,状态转移逻辑也要复杂多了。

从时序图中可以看到Mealy输出紧紧跟随上升边沿,Moore输出在时钟tick之后上升。我们可以看到Moore输出是一个
时钟周期的宽度,而Mealy输出一般小于一个时钟周期。
从上面的例子可以发现Mealy FSM需要更少的状态和逻辑,并比Moore FSM反应更快。但是,在一个Mealy中,组合电路可能在更大规模需求上。
很多时候都是用FSM做通信,这个组合通路可能很长,其次,如果FSM的通信形成一个圆圈,会造成组合闭环,在同步电路设计中是错误的。
总结来说,Moore FSM在状态机间通信的组合是更好的选择,它们比Mealy FSM更稳定。使用Mealy FSM只是当关注在相同周期的反应下更为重要。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-9-1 10:31:04 | 显示全部楼层
对应的verilog文件内容如下:
module RisingEdge3state(
  input   clock,
  input   reset,
  input   io_din,
  output  io_risingEdge
);
  reg [1:0] stateReg; // @[RisingEdge3state.scala 13:25]
  reg [31:0] _RAND_0;
  wire  _T = 2'h0 == stateReg; // @[Conditional.scala 37:30]
  wire  _T_1 = 2'h1 == stateReg; // @[Conditional.scala 37:30]
  wire  _T_2 = 2'h2 == stateReg; // @[Conditional.scala 37:30]
  wire  _T_3 = ~io_din; // @[RisingEdge3state.scala 34:12]
  assign io_risingEdge = stateReg == 2'h1; // @[RisingEdge3state.scala 39:17]

  always @(posedge clock) begin
    if (reset) begin
      stateReg <= 2'h0;
    end else if (_T) begin
      if (io_din) begin
        stateReg <= 2'h1;
      end
    end else if (_T_1) begin
      if (io_din) begin
        stateReg <= 2'h2;
      end else begin
        stateReg <= 2'h0;
      end
    end else if (_T_2) begin
      if (_T_3) begin
        stateReg <= 2'h0;
      end
    end
  end
endmodule
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-4-29 13:25 , Processed in 0.016895 second(s), 18 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表