Home > Blockchain >  RegInit initializes value only on reset
RegInit initializes value only on reset

Time:01-25

I am implementing a pulse width modulation module to learn chisel3.
The module code is:

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
}

I was expecting the registers to be initialized to their RegInit values when I emit verilog with:

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

But I get the following verilog code:

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

Note that in the code context_ is set to 0 when reset is high but it is not initialized that way. Is there an emission argument that allows registers to be initialized with the RegInit value?

CodePudding user response:

In Chisel 3, RegInit is referring to a register with reset. There is experimental support for treating an asynchronous reset line as an "initial" line instead, but I want to caution that it's not something I would recommend using in typical digital design.

As you are probably aware, initial values are not universally supported in actual hardware. They are supported by some (but not all) FPGAs, and are not supported at all in ASICs. Thus writing code that relies on initial values is inherently unportable which runs counter to the ethos of Chisel for constructing resuable hardware generators.

That being said, they can make certain designs use resources on certain FPGAs much more efficiently, so we do have a way to do this:

// 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)
    })
}

I've tweaked your design to use async reset and used the experimental support for emitting initial values. (Scastie: https://scastie.scala-lang.org/rQtHVUCZROul4i1uEjClPw)

This is using Chisel v3.5.0. There is an important bug that was recently fixed (fix to be released in v3.5.1), and there is active discussion on how to expose this experimental API directly in Chisel without having to use FIRRTL annotations: https://github.com/chipsalliance/chisel3/pull/2330.

  •  Tags:  
  • Related