RegInit 仅在复位时初始化值

RegInit initializes value only on reset

我正在实现一个脉宽调制模块来学习chisel3。
模块代码为:

import chisel3._
import chisel3.util._
import chisel3.tester._

class Pwm(bitWidth: Int) extends Module {
    val io = IO(new Bundle {
        val duty = Input(UInt(bitWidth.W))
        val period = Input(UInt(bitWidth.W))
        val output = Output(Bool())
    })

    val context = RegInit(0.U(bitWidth.W))
    val output = RegInit(false.B)
    val sum = Wire(UInt(bitWidth.W + 1))
    sum := context +& io.duty

    when (sum >= io.period) {
        context := sum - io.period
        output := true.B
    } otherwise {
        context := sum
        output := false.B
    }

    io.output := output
}

当我发出 verilog 时,我期望寄存器被初始化为它们的 RegInit 值:

val emit_args = Array("--emission-options=disableMemRandomization,disableRegisterRandomization");
chisel3.emitVerilog(new Pwm(8), emit_args)

但我得到了以下verilog代码:

module Pwm(
  input        clock,
  input        reset,
  input  [7:0] io_duty,
  input  [7:0] io_period,
  output       io_output
);
  reg [7:0] context_; // @[Pwm.scala 12:26]
  reg  output_; // @[Pwm.scala 13:25]
  wire [8:0] sum = context_ + io_duty; // @[Pwm.scala 15:20]
  wire [8:0] _GEN_2 = {{1'd0}, io_period}; // @[Pwm.scala 17:15]
  wire  _T = sum >= _GEN_2; // @[Pwm.scala 17:15]
  wire [8:0] _context_T_1 = sum - _GEN_2; // @[Pwm.scala 18:24]
  wire [8:0] _GEN_0 = sum >= _GEN_2 ? _context_T_1 : sum; // @[Pwm.scala 17:29 18:17 21:17]
  wire [8:0] _GEN_4 = reset ? 9'h0 : _GEN_0; // @[Pwm.scala 12:{26,26}]
  assign io_output = output_; // @[Pwm.scala 25:15]
  always @(posedge clock) begin
    context_ <= _GEN_4[7:0]; // @[Pwm.scala 12:{26,26}]
    if (reset) begin // @[Pwm.scala 13:25]
      output_ <= 1'h0; // @[Pwm.scala 13:25]
    end else begin
      output_ <= _T;
    end
  end
endmodule

请注意,在代码中 context_ 在重置为高电平时设置为 0,但不会以这种方式进行初始化。 是否有允许使用 RegInit 值初始化寄存器的发射参数?

在 Chisel 3 中,RegInit 指的是具有复位功能的寄存器。实验性支持将异步复位线视为“初始”线,但我想提醒的是,我不建议在典型的数字设计中使用它。

您可能已经知道,实际硬件并不普遍支持初始值。一些(但不是全部)FPGA 支持它们,而 ASIC 则完全不支持它们。因此,编写依赖于初始值的代码本质上是不可移植的,这与 Chisel 构建 可重用 硬件生成器的精神背道而驰。

也就是说,他们可以让某些设计更有效地使用某些 FPGA 上的资源,所以我们确实有办法做到这一点:

// RequireAsyncReset makes the implicit reset Async because the default is Sync (only for top-level module)
// Only AsyncReset can be emitted as an initial value
class Pwm(bitWidth: Int) extends Module with RequireAsyncReset {

    val io = IO(new Bundle {
        val duty = Input(UInt(bitWidth.W))
        val period = Input(UInt(bitWidth.W))
        val output = Output(Bool())
    })

    val context = RegInit(0.U(bitWidth.W))
    val output = RegInit(false.B)
    val sum = Wire(UInt(bitWidth.W + 1))
    sum := context +& io.duty

    when (sum >= io.period) {
        context := sum - io.period
        output := true.B
    } otherwise {
        context := sum
        output := false.B
    }

    io.output := output
  
    // Experimental API
    annotate(new ChiselAnnotation {
      def toFirrtl = firrtl.annotations.PresetAnnotation(reset.toTarget)
    })
}

我已将您的设计调整为使用异步重置并使用实验性支持发出初始值。 (斯卡斯蒂:https://scastie.scala-lang.org/rQtHVUCZROul4i1uEjClPw

这是使用 Chisel v3.5.0。最近修复了一个重要的错误(修复将在 v3.5.1 中发布),并且正在积极讨论如何在 Chisel 中直接公开此实验 API 而无需使用 FIRRTL 注释:https://github.com/chipsalliance/chisel3/pull/2330.