如何在 Chisel 中正确定义输出 Reg

How to define output Reg in Chisel properly

您可能了解 Verilog 中的 "output reg",非常有用的功能。
但是在 Chisel 中我找不到如何做类似的事情。当我需要寄存器输出时,我应该这样做:

package filter

import chisel3._

class TestReg extends Module {
    val io = IO( new Bundle {
        val din  = Input(SInt(32.W))
        val ena  = Input(Bool())
        val dout = Output(SInt())
    })

    val dout = RegInit(0.S(32.W))
    when (io.ena) {
        dout := io.din + 77.S
    }
    io.dout <> dout
}

是否有更多 "short" 方法来创建输出 reg?
我正在寻找的是在 IO bundle 中定义 Reg 并将其写入 register
像这样:

class TestReg extends Module {
    val io = IO( new Bundle {
        val din  = Input(SInt(32.W))
        val ena  = Input(Bool())
        val dout = Output(RegInit(0.S(32.W)))
    })

    when (io.ena) {
        io.dout := io.din + 77.S
    }
}

Bundle 中不允许使用寄存器以保持其作为接口的纯度。它们比 Verilog 95/2001 端口声明更接近 SystemVerilog 结构。

使用现有的库,最简单的方法就是使用 RegNext:

io.dout := RegNext(io.din + 77.S, 0.S(32.W))

注意:在 FIRRTL 编译器推断宽度之前,这不会设置 io.dout 的宽度。如果您尝试为某些东西获取 io.dout 的宽度,这有时会导致问题。

忽略标准库,您也可以通过定义自己的实用程序以两种可能的方式之一创建注册连接来更手动地执行此操作:

  1. 创建一个函数来执行 "registered" 连接
object ConnectionUtilities {
  def regConnect(lhs: Data, rhs: Data): Unit = {
    val rhsReg = Reg(chiselTypeOf(rhs))
    rhsReg := rhs
    lhs := rhsReg
  }
}

有了这个,你就可以使用这个方法进行连接并生成必要的寄存器:

import ConnectionUtilities.regConnect

regConnect(io.out, io.in + 77.S)
  1. 创建隐式 class 以将方法添加到 Data。这是更高级的,有可能使阅读您的代码的人感到困惑。但是,它允许您使用自己的领域特定语言扩展 Chisel 领域特定语言。
object ConnectUtilities2 {
  implicit class DataWithRegConnect(lhs: Data) {
    def `:=r` (rhs: Data): Unit = {
      val rhsReg = Reg(chiselTypeOf(rhs))
      rhsReg := rhs
      lhs := rhsReg
    }
  }
}

然后您可以使用这个新方法(注意这需要反引号,因为 :=r 本身不是合法名称)。

import ConnectUtilities2.DataWithRegConnect

io.dout `:=r` (io.din + 77.S)