General Cookbook

Please note that these examples make use of Chisel’s scala-style printing.

Converting Chisel Types to/from UInt

How do I create a UInt from an instance of a Bundle?

Call asUInt on the Bundle instance.

import chisel3._

class MyBundle extends Bundle {
  val foo = UInt(4.W)
  val bar = UInt(4.W)
}

class Foo extends RawModule {
  val bundle = Wire(new MyBundle)
  bundle.foo := 0xc.U
  bundle.bar := 0x3.U
  val uint = bundle.asUInt
}

How do I create a Bundle from a UInt?

Use the asTypeOf method to reinterpret the UInt as the type of the Bundle.

import chisel3._

class MyBundle extends Bundle {
  val foo = UInt(4.W)
  val bar = UInt(4.W)
}

class Foo extends RawModule {
  val uint = 0xb4.U
  val bundle = uint.asTypeOf(new MyBundle)
}

How can I tieoff a Bundle/Vec to 0?

You can use asTypeOf as above. If you don’t want to worry about the type of the thing you are tying off, you can use chiselTypeOf:

import chisel3._

class MyBundle extends Bundle {
  val foo = UInt(4.W)
  val bar = Vec(4, UInt(1.W))
}

class Foo(typ: Data) extends RawModule {
  val bundleA = IO(Output(typ))
  val bundleB = IO(Output(typ))
  
  // typ is already a Chisel Data Type, so can use it directly here, but you 
  // need to know that bundleA is of type typ
  bundleA := 0.U.asTypeOf(typ)
  
  // bundleB is a Hardware data IO(Output(...)) so need to call chiselTypeOf,
  // but this will work no matter the type of bundleB:
  bundleB := 0.U.asTypeOf(chiselTypeOf(bundleB)) 
}

class Bar extends RawModule {
  val foo = Module(new Foo(new MyBundle()))
}

How do I create a Vec of Bools from a UInt?

Use VecInit given a Seq[Bool] generated using the asBools method.

import chisel3._

class Foo extends RawModule {
  val uint = 0xc.U
  val vec = VecInit(uint.asBools)
}

How do I create a UInt from a Vec of Bool?

Use the builtin function asUInt

import chisel3._

class Foo extends RawModule {
  val vec = VecInit(true.B, false.B, true.B, true.B)
  val uint = vec.asUInt
}

Vectors and Registers

How do I create a Vector of Registers?

Rule! Use Reg of Vec not Vec of Reg!

You create a Reg of type Vec. Because Vecs are a type (like UInt, Bool) rather than a value, we must bind the Vec to some concrete value.

How do I create a Reg of type Vec?

For more information, the API Documentation for Vec provides more information.

import chisel3._

class Foo extends RawModule {
  val regOfVec = Reg(Vec(4, UInt(32.W))) // Register of 32-bit UInts
  regOfVec(0) := 123.U                   // Assignments to elements of the Vec
  regOfVec(1) := 456.U
  regOfVec(2) := 789.U
  regOfVec(3) := regOfVec(0)

  // Reg of Vec of 32-bit UInts initialized to zero
  //   Note that Seq.fill constructs 4 32-bit UInt literals with the value 0
  //   VecInit(...) then constructs a Wire of these literals
  //   The Reg is then initialized to the value of the Wire (which gives it the same type)
  val initRegOfVec = RegInit(VecInit(Seq.fill(4)(0.U(32.W))))
}

How do I create a finite state machine (FSM)?

The advised way is to use ChiselEnum to construct enumerated types representing the state of the FSM. State transitions are then handled with switch/is and when/.elsewhen/.otherwise.

import chisel3._
import chisel3.util.{switch, is}
import chisel3.experimental.ChiselEnum

object DetectTwoOnes {
  object State extends ChiselEnum {
    val sNone, sOne1, sTwo1s = Value
  }
}

/* This FSM detects two 1's one after the other */
class DetectTwoOnes extends Module {
  import DetectTwoOnes.State
  import DetectTwoOnes.State._

  val io = IO(new Bundle {
    val in = Input(Bool())
    val out = Output(Bool())
    val state = Output(State())
  })

  val state = RegInit(sNone)

  io.out := (state === sTwo1s)
  io.state := state

  switch (state) {
    is (sNone) {
      when (io.in) {
        state := sOne1
      }
    }
    is (sOne1) {
      when (io.in) {
        state := sTwo1s
      } .otherwise {
        state := sNone
      }
    }
    is (sTwo1s) {
      when (!io.in) {
        state := sNone
      }
    }
  }
}

Note: the is statement can take multiple conditions e.g. is (sTwo1s, sOne1) { ... }.

How do I unpack a value (“reverse concatenation”) like in Verilog?

In Verilog, you can do something like the following which will unpack a the value z:

wire [1:0] a;
wire [3:0] b;
wire [2:0] c;
wire [8:0] z = [...];
assign {a,b,c} = z;

Unpacking often corresponds to reinterpreting an unstructured data type as a structured data type. Frequently, this structured type is used prolifically in the design, and has been declared as in the following example:

import chisel3._

class MyBundle extends Bundle {
  val a = UInt(2.W)
  val b = UInt(4.W)
  val c = UInt(3.W)
}

The easiest way to accomplish this in Chisel would be:

class Foo extends RawModule {
  val z = Wire(UInt(9.W))
  z := DontCare // This is a dummy connection
  val unpacked = z.asTypeOf(new MyBundle)
  printf("%d", unpacked.a)
  printf("%d", unpacked.b)
  printf("%d", unpacked.c)
}

If you really need to do this for a one-off case (Think thrice! It is likely you can better structure the code using bundles), then rocket-chip has a Split utility which can accomplish this.

How do I do subword assignment (assign to some bits in a UInt)?

You may try to do something like the following where you want to assign only some bits of a Chisel type. Below, the left-hand side connection to io.out(0) is not allowed.

import chisel3._
import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}

class Foo extends Module {
  val io = IO(new Bundle {
    val bit = Input(Bool())
    val out = Output(UInt(10.W))
  })
  io.out(0) := io.bit
}

If you try to compile this, you will get an error.

(new ChiselStage).execute(Array("-X", "verilog"), Seq(new ChiselGeneratorAnnotation(() => new Foo)))
// chisel3.internal.ChiselException: Cannot reassign to read-only Bool(OpResult in Foo)
// 	at ... ()
// 	at repl.MdocSession$App8$Foo.<init>(cookbook.md:242)
// 	at repl.MdocSession$App8$$anonfun$51$$anonfun$apply$27.apply(cookbook.md:250)
// 	at repl.MdocSession$App8$$anonfun$51$$anonfun$apply$27.apply(cookbook.md:250)
// 	at ... ()
// 	at ... (Stack trace trimmed to user code only. Rerun with --full-stacktrace to see the full stack trace)

Chisel3 does not support subword assignment. The reason for this is that subword assignment generally hints at a better abstraction with an aggregate/structured types, i.e., a Bundle or a Vec.

If you must express it this way, one approach is to blast your UInt to a Vec of Bool and back:

import chisel3._

class Foo extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(10.W))
    val bit = Input(Bool())
    val out = Output(UInt(10.W))
  })
  val bools = VecInit(io.in.asBools)
  bools(0) := io.bit
  io.out := bools.asUInt
}

How do I create an optional I/O?

The following example is a module which includes the optional port out2 only if the given parameter is true.

import chisel3._

class ModuleWithOptionalIOs(flag: Boolean) extends Module {
  val io = IO(new Bundle {
    val in = Input(UInt(12.W))
    val out = Output(UInt(12.W))
    val out2 = if (flag) Some(Output(UInt(12.W))) else None
  })

  io.out := io.in
  if (flag) {
    io.out2.get := io.in
  }
}

The following is an example for a MultiIOModule where an entire IO is optional:

import chisel3._

class ModuleWithOptionalIO(flag: Boolean) extends MultiIOModule {
  val in = if (flag) Some(IO(Input(Bool()))) else None
  val out = IO(Output(Bool()))

  out := in.getOrElse(false.B)
}

Predictable Naming

How do I get Chisel to name signals properly in blocks like when/withClockAndReset?

To get Chisel to name signals (wires and registers) declared inside of blocks like when, withClockAndReset, etc, use the @chiselName annotation as shown below:

import chisel3._
import chisel3.experimental.chiselName

@chiselName
class TestMod extends Module {
  val io = IO(new Bundle {
    val a = Input(Bool())
    val b = Output(UInt(4.W))
  })
  when (io.a) {
    val innerReg = RegInit(5.U(4.W))
    innerReg := innerReg + 1.U
    io.b := innerReg
  } .otherwise {
    io.b := 10.U
  }
}

Note that you will need to add the following line to your project’s build.sbt file.

addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)

If we compile this module without @chiselName, Chisel is not able to name innerReg correctly (notice the _T):

Elaborating design… [deprecated] class repl.MdocSession$App12$TestModWithout\(anonfun$76\)anonfun$apply$36\(anon$6 (1 calls): chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance. Autoclonetype failure reason: Unable to determine instance of outer class class repl.MdocSession$App12$TestModWithout\)anonfun$76$$anonfun$apply$36, no candidates assignable to outer class types; examined List(repl.MdocSession$App12$TestModWithout@21e58a4a) [warn] There were 1 deprecated function(s) used. These may stop compiling in a future release - you are encouraged to fix these issues. [warn] Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods: [warn] In the sbt interactive console, enter: [warn] set scalacOptions in ThisBuild ++= Seq(“-unchecked”, “-deprecation”) [warn] or, in your build.sbt, add the line: [warn] scalacOptions := Seq(“-unchecked”, “-deprecation”) Done elaborating.

However, if we use @chiselName then the register previously called _T is now innerReg: Elaborating design… [deprecated] class repl.MdocSession$App12$TestMod\(anonfun$69\)anonfun$apply$34\(anon$5 (1 calls): chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance. Autoclonetype failure reason: Unable to determine instance of outer class class repl.MdocSession$App12$TestMod\)anonfun$69$$anonfun$apply$34, no candidates assignable to outer class types; examined List(repl.MdocSession$App12$TestMod@7d7b84c9) [warn] There were 1 deprecated function(s) used. These may stop compiling in a future release - you are encouraged to fix these issues. [warn] Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods: [warn] In the sbt interactive console, enter: [warn] set scalacOptions in ThisBuild ++= Seq(“-unchecked”, “-deprecation”) [warn] or, in your build.sbt, add the line: [warn] scalacOptions := Seq(“-unchecked”, “-deprecation”) Done elaborating.

How do I get Chisel to name the results of vector reads properly?

Currently, name information is lost when using dynamic indexing. For example:

class Foo extends Module {
  val io = IO(new Bundle {
    val in = Input(Vec(4, Bool()))
    val idx = Input(UInt(2.W))
    val en = Input(Bool())
    val out = Output(Bool())
  })

  val x = io.in(io.idx)
  val y = x && io.en
  io.out := y
}

The above code loses the x name, instead using _GEN_3 (the other _GEN_* signals are expected).

module Foo(
  input        clock,
  input        reset,
  input        io_in_0,
  input        io_in_1,
  input        io_in_2,
  input        io_in_3,
  input  [1:0] io_idx,
  input        io_en,
  output       io_out
);
  wire  _GEN_1; // @[main.scala 15:13]
  wire  _GEN_2; // @[main.scala 15:13]
  wire  _GEN_3; // @[main.scala 15:13]
  assign _GEN_1 = 2'h1 == io_idx ? io_in_1 : io_in_0; // @[main.scala 15:13]
  assign _GEN_2 = 2'h2 == io_idx ? io_in_2 : _GEN_1; // @[main.scala 15:13]
  assign _GEN_3 = 2'h3 == io_idx ? io_in_3 : _GEN_2; // @[main.scala 15:13]
  assign io_out = _GEN_3 & io_en; // @[main.scala 16:10]
endmodule

This can be worked around by creating a wire and connecting the dynamic index to the wire:

val x = WireInit(io.in(io.idx))

Which produces:

module Foo(
  input        clock,
  input        reset,
  input        io_in_0,
  input        io_in_1,
  input        io_in_2,
  input        io_in_3,
  input  [1:0] io_idx,
  input        io_en,
  output       io_out
);
  wire  _GEN_1;
  wire  _GEN_2;
  wire  x;
  assign _GEN_1 = 2'h1 == io_idx ? io_in_1 : io_in_0;
  assign _GEN_2 = 2'h2 == io_idx ? io_in_2 : _GEN_1;
  assign x = 2'h3 == io_idx ? io_in_3 : _GEN_2;
  assign io_out = x & io_en; // @[main.scala 16:10]
endmodule

How can I dynamically set/parametrize the name of a module?

You can override the desiredName function. This works with normal Chisel modules and BlackBoxes. Example:

import chisel3._

class Coffee extends BlackBox {
    val io = IO(new Bundle {
        val I = Input(UInt(32.W))
        val O = Output(UInt(32.W))
    })
    override def desiredName = "Tea"
}

class Salt extends Module {
    val io = IO(new Bundle {})
    val drink = Module(new Coffee)
    override def desiredName = "SodiumMonochloride"
}

Elaborating the Chisel module Salt yields our “desire name” for Salt and Coffee in the output Verilog: Elaborating design… [deprecated] class repl.MdocSession$App15$Salt\(anonfun$102\)anonfun$apply$42\(anon$9 (1 calls): chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance. Autoclonetype failure reason: Unable to determine instance of outer class class repl.MdocSession$App15$Salt\)anonfun$102\(anonfun$apply$42, no candidates assignable to outer class types; examined List(repl.MdocSession$App15$Salt@63830f61) [deprecated] class repl.MdocSession$App15$Coffee\)anonfun$99\(anonfun$apply$41\)anon$8 (1 calls): chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance. Autoclonetype failure reason: Unable to determine instance of outer class class repl.MdocSession$App15$Coffee\(anonfun$99\)anonfun$apply$41, no candidates assignable to outer class types; examined List(repl.MdocSession$App15$Coffee@209dd249) [warn] There were 2 deprecated function(s) used. These may stop compiling in a future release - you are encouraged to fix these issues. [warn] Line numbers for deprecations reported by Chisel may be inaccurate; enable scalac compiler deprecation warnings via either of the following methods: [warn] In the sbt interactive console, enter: [warn] set scalacOptions in ThisBuild ++= Seq(“-unchecked”, “-deprecation”) [warn] or, in your build.sbt, add the line: [warn] scalacOptions := Seq(“-unchecked”, “-deprecation”) Done elaborating.