chisel边沿检测电路实现(Reg延迟特性)

一、代码设计

  • chisel代码
import chisel3._
import chisel3.util._
import chisel3.stage._

class EdgeDetect(resetValue: Option[UInt] = None) extends Module {
    val io = IO(new Bundle {
        val in  = Input(UInt(1.W))
        val pos = Output(UInt(1.W))
        val neg = Output(UInt(1.W))
    })
    val reg = if (resetValue.isDefined) { // resetValue = Some(number)
        RegInit(resetValue.get)
    } else { //resetValue = None
        Reg(UInt())
    }
    
    reg := io.in
    
    when((reg===0.U)&&(io.in===1.U)){
        io.pos := 1.U
        io.neg := 0.U
    }.elsewhen((reg===1.U)&&(io.in===0.U)){
        io.pos := 0.U
        io.neg := 1.U
    }.otherwise {
        io.pos := 0.U
        io.neg := 0.U
    }
        
}

// Generate the Verilog code
object EdgeDetectMain extends App {
  println("Generating the EdgeDetect hardware")
  
  (new chisel3.stage.ChiselStage).execute(Array("--target-dir", "generated"), 
  							Seq(ChiselGeneratorAnnotation(() => new EdgeDetect(Some(1.U)))))
}
  • 生成的verilog代码主体部分
module EdgeDetect(
  input   clock,
  input   reset,
  input   io_in,
  output  io_pos,
  output  io_neg
);
`ifdef RANDOMIZE_REG_INIT
  reg [31:0] _RAND_0;
`endif // RANDOMIZE_REG_INIT
  reg  reg_; // @[EdgeDetect.scala 14:16]
  wire  _T_5 = reg_ & ~io_in; // @[EdgeDetect.scala 24:27]
  assign io_pos = ~reg_ & io_in; // @[EdgeDetect.scala 21:21]
  assign io_neg = ~reg_ & io_in ? 1'h0 : _T_5; // @[EdgeDetect.scala 21:37 EdgeDetect.scala 23:16]
  always @(posedge clock) begin
    reg_ <= reset | io_in; // @[EdgeDetect.scala 14:16 EdgeDetect.scala 14:16 EdgeDetect.scala 19:9]
  end

endmodule

二、代码分析

	reg := io.in
    
    when((reg===0.U)&&(io.in===1.U)){
        io.pos := 1.U
        io.neg := 0.U
    }.elsewhen((reg===1.U)&&(io.in===0.U)){
        io.pos := 0.U
        io.neg := 1.U
    }.otherwise {
        io.pos := 0.U
        io.neg := 0.U
    }

整个代码的核心部分就是上面这段,我们之所以可以通过这种形式获得信号的边沿信息,是因为Reg的延迟特性,也即只要你将一个信号赋值给Reg,那么此时你就可以理解为你获得了延迟一个clk后的该信号。

同时拥有了当前clk(端口io.in)和延迟一个clk(定义的reg)的信号之后,就和我们在verilog中进行边沿检测的方式完全一样了。从生成的verilog代码中也可以验证这一点。具体可以参考我的另一篇文章:

Verilog边沿检测电路设计


还有一点需要注意的是:

例如我们在测试时,执行了io.in.poke(1.U),此时如果你不执行step(1),从代码的角度看,可以理解为此时的reg并没有被赋值,或者说还没被更新,也即reg != 1.U。chisel虽然是高级语言的写法,但是我们必须时刻记得这是在设计硬件电路。

因此,step(1)写在expect()前面和后面两种情况下,有时候就会产生不一样的结果。如果不想出错,一点要谨记上面所说的点:

  • 如果写在了expect()前面,此时poke的新数据已经更新给了reg,那么就可以根据新数据计算实际结果,然后和模型输出作比较;
  • 如果写在了expect()后面,那么poke的新数据还未更新给reg,就不能使用新数据计算实际结果,否则和模型输出进行比较的时候,两者是不一致的,就会报错。

不过具体情况还需具体分析,只需要注意reg的延迟特性即可!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

耐心的小黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值