Skip to main content

# Naming

Historically, Chisel has had trouble reliably capturing the names of signals. The reasons for this are due to (1) primarily relying on reflection to find names, (2) using `@chiselName` macro which had unreliable behavior.

Chisel 3.4 introduced a custom Scala compiler plugin which enables reliabe and automatic capturing of signal names, when they are declared. In addition, this release includes prolific use of a new prefixing API which enables more stable naming of signals programmatically generated from function calls.

This document explains how naming now works in Chisel for signal and module names. For cookbook examples on how to fix systemic name-stability issues, please refer to the naming cookbook.

### Compiler Plugin​

    // Imports used by the following examples
    import chisel3._
    import chisel3.experimental.{prefix, noPrefix}

Chisel users must also include the compiler plugin in their build settings. In SBT this is something like:

    // For chisel versions 5.0.0+
    addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % "5.0.0" cross CrossVersion.full)
    // For older chisel3 versions, eg. 3.6.0
    addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.6.0" cross CrossVersion.full)

This plugin will run after the 'typer' phase of the Scala compiler. It looks for any user code which is of the form `val x = y`, where `x` is of type `chisel3.Data`, `chisel3.MemBase`, or `chisel3.experimental.BaseModule`. For each line which fits this criteria, it rewrites that line. In the following examples, the commented line is the what the line above is rewritten to.

If the line is within a bundle declaration or is a module instantiation, it is rewritten to replace the right hand side with a call to `autoNameRecursively`, which names the signal/module.

    class MyBundle extends Bundle {
      val foo = Input(UInt(3.W))
      // val foo = autoNameRecursively("foo")(Input(UInt(3.W)))
    }
    class Example1 extends Module {
      val io = IO(new MyBundle())
      // val io = autoNameRecursively("io")(IO(new MyBundle()))
    }

    // Generated by CIRCT firtool-1.76.0
    module Example1(
      input       clock,
                  reset,
      input [2:0] io_foo
    );

    endmodule

Otherwise, it is rewritten to also include the name as a prefix to any signals generated while executing the right-hand- side of the val declaration:

    class Example2 extends Module {
      val in = IO(Input(UInt(2.W)))
      // val in = autoNameRecursively("in")(prefix("in")(IO(Input(UInt(2.W)))))

      val out1 = IO(Output(UInt(4.W)))
      // val out1 = autoNameRecursively("out1")(prefix("out1")(IO(Output(UInt(4.W)))))
      val out2 = IO(Output(UInt(4.W)))
      // val out2 = autoNameRecursively("out2")(prefix("out2")(IO(Output(UInt(4.W)))))
      val out3 = IO(Output(UInt(4.W)))
      // val out3 = autoNameRecursively("out3")(prefix("out3")(IO(Output(UInt(4.W)))))

      def func() = {
        val squared = in * in
        // val squared = autoNameRecursively("squared")(prefix("squared")(in * in))
        out1 := squared
        val delay = RegNext(squared)
        // val delay = autoNameRecursively("delay")(prefix("delay")(RegNext(squared)))
        delay
      }

      val masked = 0xa.U & func()
      // val masked = autoNameRecursively("masked")(prefix("masked")(0xa.U & func()))
      // Note that values created inside of `func()`` are prefixed with `masked`

      out2 := masked + 1.U
      out3 := masked - 1.U
    }

    // Generated by CIRCT firtool-1.76.0
    module Example2(
      input        clock,
                   reset,
      input  [1:0] in,
      output [3:0] out1,
                   out2,
                   out3
    );

      wire [3:0] _GEN = {2'h0, in};
      wire [3:0] masked_squared = _GEN * _GEN;
      reg  [3:0] masked_delay;
      wire [3:0] masked = masked_delay & 4'hA;
      always @(posedge clock)
        masked_delay <= masked_squared;
      assign out1 = masked_squared;
      assign out2 = masked + 4'h1;
      assign out3 = masked - 4'h1;
    endmodule

Prefixing can also be derived from the name of signals on the left-hand side of a connection. While this is not implemented via the compiler plugin, the behavior should feel similar:

    class ConnectPrefixing extends Module {
      val in = IO(Input(UInt(2.W)))
      // val in = autoNameRecursively("in")(prefix("in")(IO(Input(UInt(2.W)))))

      val out1 = IO(Output(UInt(4.W)))
      // val out1 = autoNameRecursively("out1")(prefix("out1")(IO(Output(UInt(4.W)))))
      val out2 = IO(Output(UInt(4.W)))
      // val out2 = autoNameRecursively("out2")(prefix("out2")(IO(Output(UInt(4.W)))))

      out1 := { // technically this is not wrapped in autoNameRecursively nor prefix
        // But the Chisel runtime will still use the name of `out1` as a prefix
        val squared = in * in
        out2 := squared
        val delayed = RegNext(squared)
        // val delayed = autoNameRecursively("delayed")(prefix("delayed")(RegNext(squared)))
        delayed + 1.U
      }
    }

    // Generated by CIRCT firtool-1.76.0
    module ConnectPrefixing(
      input        clock,
                   reset,
      input  [1:0] in,
      output [3:0] out1,
                   out2
    );

      wire [3:0] _GEN = {2'h0, in};
      wire [3:0] out1_squared = _GEN * _GEN;
      reg  [3:0] out1_delayed;
      always @(posedge clock)
        out1_delayed <= out1_squared;
      assign out1 = out1_delayed + 4'h1;
      assign out2 = out1_squared;
    endmodule

Note that the naming also works if the hardware type is nested in an `Option` or a subtype of `Iterable`:

    class Example3 extends Module {
      val in = IO(Input(UInt(2.W)))
      // val in = autoNameRecursively("in")(prefix("in")(IO(Input(UInt(2.W)))))

      val out = IO(Output(UInt(4.W)))
      // val out = autoNameRecursively("out")(prefix("out")(IO(Output(UInt(4.W)))))

      def func() = {
        val delay = RegNext(in)
        delay + 1.U
      }

      val opt = Some(func())
      // Note that the register in func() is prefixed with `opt`:
      // val opt = autoNameRecursively("opt")(prefix("opt")(Some(func()))

      out := opt.get + 1.U
    }

    // Generated by CIRCT firtool-1.76.0
    module Example3(
      input        clock,
                   reset,
      input  [1:0] in,
      output [3:0] out
    );

      reg [1:0] opt_delay;
      always @(posedge clock)
        opt_delay <= in;
      assign out = {2'h0, opt_delay - 2'h2};
    endmodule

There is also a slight variant (`autoNameRecursivelyProduct`) for naming hardware with names provided by an unapply:

    class UnapplyExample extends Module {
      def mkIO() = (IO(Input(UInt(2.W))), IO(Output(UInt(2.W))))
      val (in, out) = mkIO()
      // val (in, out) = autoNameRecursivelyProduct(List(Some("in"), Some("out")))(mkIO())

      out := in
    }

    // Generated by CIRCT firtool-1.76.0
    module UnapplyExample(
      input        clock,
                   reset,
      input  [1:0] in,
      output [1:0] out
    );

      assign out = in;
    endmodule

Note that the compiler plugin will not insert a prefix in these cases because it is ambiguous what the prefix should be. Users who desire a prefix are encouraged to provide one as described below.

### Prefixing​

As shown above, the compiler plugin automatically attempts to prefix some of your signals for you. However, you as a user can also add your own prefixes by calling `prefix(...)`:

Also note that the prefixes append to each other (including the prefix generated by the compiler plugin):

    class Example6 extends Module {
      val in = IO(Input(UInt(2.W)))
      val out = IO(Output(UInt(4.W)))

      val add = prefix("foo") {
        val sum = RegNext(in + 1.U)
        sum + 1.U
      }

      out := add
    }

    // Generated by CIRCT firtool-1.76.0
    module Example6(
      input        clock,
                   reset,
      input  [1:0] in,
      output [3:0] out
    );

      reg [1:0] add_foo_sum;
      always @(posedge clock)
        add_foo_sum <= in + 2'h1;
      assign out = {2'h0, add_foo_sum + 2'h1};
    endmodule

Sometimes you may want to disable the prefixing. This might occur if you are writing a library function and don't want the prefixing behavior. In this case, you can call `noPrefix`:

    class Example7 extends Module {
      val in = IO(Input(UInt(2.W)))
      val out = IO(Output(UInt(4.W)))

      val add = noPrefix {
        val sum = RegNext(in + 1.U)
        sum + 1.U
      }

      out := add
    }

    // Generated by CIRCT firtool-1.76.0
    module Example7(
      input        clock,
                   reset,
      input  [1:0] in,
      output [3:0] out
    );

      reg [1:0] sum;
      always @(posedge clock)
        sum <= in + 2'h1;
      assign out = {2'h0, sum + 2'h1};
    endmodule

### Suggest a Signal's Name (or the instance name of a Module)​

If you want to specify the name of a signal, you can always use the `.suggestName` API. Please note that the suggested name will still be prefixed (including by the plugin). You can always use the `noPrefix` object to strip this.

    class Example8 extends Module {
      val in = IO(Input(UInt(2.W)))
      val out = IO(Output(UInt(4.W)))

      val add = {
        val sum = RegNext(in + 1.U).suggestName("foo")
        sum + 1.U
      }

      out := add
    }

    // Generated by CIRCT firtool-1.76.0
    module Example8(
      input        clock,
                   reset,
      input  [1:0] in,
      output [3:0] out
    );

      reg [1:0] add_foo;
      always @(posedge clock)
        add_foo <= in + 2'h1;
      assign out = {2'h0, add_foo + 2'h1};
    endmodule

Note that using `.suggestName` does not affect prefixes derived from val names; however, it can affect prefixes derived from connections (eg. `:=`):

    class ConnectionPrefixExample extends Module {
      val in0 = IO(Input(UInt(2.W)))
      val in1 = IO(Input(UInt(2.W)))

      val out0 = {
        val port = IO(Output(UInt(5.W)))
        // Even though this suggestName is before mul, the prefix used in this scope
        // is derived from `val out0`, so this does not affect the name of mul
        port.suggestName("foo")
        // out0_mul
        val mul = RegNext(in0 * in1)
        port := mul + 1.U
        port
      }

      val out1 = IO(Output(UInt(4.W)))
      val out2 = IO(Output(UInt(4.W)))

      out1 := {
        // out1_sum
        val sum = RegNext(in0 + in1)
        sum + 1.U
      }
      // Comes after so does *not* affect prefix above
      out1.suggestName("bar")

      // Comes before so *does* affect prefix below
      out2.suggestName("fizz")
      out2 := {
        // fizz_diff
        val diff = RegNext(in0 - in1)
        diff + 1.U
      }
    }

    // Generated by CIRCT firtool-1.76.0
    module ConnectionPrefixExample(
      input        clock,
                   reset,
      input  [1:0] in0,
                   in1,
      output [4:0] foo,
      output [3:0] bar,
                   fizz
    );

      reg [3:0] out0_mul;
      reg [1:0] out1_sum;
      reg [1:0] fizz_diff;
      always @(posedge clock) begin
        out0_mul <= {2'h0, in0} * {2'h0, in1};
        out1_sum <= in0 + in1;
        fizz_diff <= in0 - in1;
      end // always @(posedge)
      assign foo = {1'h0, out0_mul + 4'h1};
      assign bar = {2'h0, out1_sum + 2'h1};
      assign fizz = {2'h0, fizz_diff + 2'h1};
    endmodule

As this example illustrates, this behavior is slightly inconsistent so is subject to change in a future version of Chisel.

### Behavior for "Unnamed signals" (aka "Temporaries")​

If you want to signify that the name of a signal does not matter, you can prefix the name of your val with `_`. Chisel will preserve the convention of leading `_` signifying an unnamed signal across prefixes. For example:

    class TemporaryExample extends Module {
      val in0 = IO(Input(UInt(2.W)))
      val in1 = IO(Input(UInt(2.W)))

      val out = {
        // We need 2 ports so firtool will maintain the common subexpression
        val port0 = IO(Output(UInt(4.W)))
        // out_port1
        val port1 = IO(Output(UInt(4.W)))
        val _sum = in0 + in1
        port0 := _sum + 1.U
        port1 := _sum - 1.U
        // port0 is returned so will get the name "out"
        port0
      }
    }

    // Generated by CIRCT firtool-1.76.0
    module TemporaryExample(
      input        clock,
                   reset,
      input  [1:0] in0,
                   in1,
      output [3:0] out,
                   out_port1
    );

      wire [1:0] _out_sum_T = in0 + in1;
      assign out = {2'h0, _out_sum_T + 2'h1};
      assign out_port1 = {2'h0, _out_sum_T - 2'h1};
    endmodule

If an unnamed signal is itself used to generate a prefix, the leading `_` will be ignored to avoid double `__` in the names of further nested signals.

    class TemporaryPrefixExample extends Module {
      val in0 = IO(Input(UInt(2.W)))
      val in1 = IO(Input(UInt(2.W)))
      val out0 = IO(Output(UInt(3.W)))
      val out1 = IO(Output(UInt(4.W)))

      val _sum = {
        val x = in0 + in1
        out0 := x
        x + 1.U
      }
      out1 := _sum & 0x2.U
    }

    // Generated by CIRCT firtool-1.76.0
    module TemporaryPrefixExample(
      input        clock,
                   reset,
      input  [1:0] in0,
                   in1,
      output [2:0] out0,
      output [3:0] out1
    );

      wire [1:0] _sum_x_T = in0 + in1;
      assign out0 = {1'h0, _sum_x_T};
      assign out1 = {2'h0, _sum_x_T + 2'h1 & 2'h2};
    endmodule

### Set a Module Name​

If you want to specify the module's name (not the instance name of a module), you can always override the `desiredName` value. Note that you can parameterize the name by the module's parameters. This is an excellent way to make your module names more stable and is highly recommended to do.

    class Example9(width: Int) extends Module {
      override val desiredName = s"EXAMPLE9WITHWIDTH$width"
      val in = IO(Input(UInt(width.W)))
      val out = IO(Output(UInt((width + 2).W)))

      val add = (in + (in + in).suggestName("foo"))

      out := add
    }

    // Generated by CIRCT firtool-1.76.0
    module EXAMPLE9WITHWIDTH8(
      input        clock,
                   reset,
      input  [7:0] in,
      output [9:0] out
    );

      assign out = {2'h0, in + {in[6:0], 1'h0}};
    endmodule

    // Generated by CIRCT firtool-1.76.0
    module EXAMPLE9WITHWIDTH1(
      input        clock,
                   reset,
                   in,
      output [2:0] out
    );

      assign out = {2'h0, in};
    endmodule