summaryrefslogtreecommitdiff
path: root/docs/src/cookbooks
diff options
context:
space:
mode:
Diffstat (limited to 'docs/src/cookbooks')
-rw-r--r--docs/src/cookbooks/cookbook.md564
-rw-r--r--docs/src/cookbooks/cookbooks.md15
-rw-r--r--docs/src/cookbooks/dataview.md179
-rw-r--r--docs/src/cookbooks/hierarchy.md204
-rw-r--r--docs/src/cookbooks/troubleshooting.md64
5 files changed, 1026 insertions, 0 deletions
diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md
new file mode 100644
index 00000000..ce49b668
--- /dev/null
+++ b/docs/src/cookbooks/cookbook.md
@@ -0,0 +1,564 @@
+---
+layout: docs
+title: "General Cookbook"
+section: "chisel3"
+---
+
+# General Cookbook
+
+
+Please note that these examples make use of [Chisel's scala-style printing](../explanations/printing#scala-style).
+
+* Type Conversions
+ * [How do I create a UInt from an instance of a Bundle?](#how-do-i-create-a-uint-from-an-instance-of-a-bundle)
+ * [How do I create a Bundle from a UInt?](#how-do-i-create-a-bundle-from-a-uint)
+ * [How can I tieoff a Bundle/Vec to 0?](#how-can-i-tieoff-a-bundlevec-to-0)
+ * [How do I create a Vec of Bools from a UInt?](#how-do-i-create-a-vec-of-bools-from-a-uint)
+ * [How do I create a UInt from a Vec of Bool?](#how-do-i-create-a-uint-from-a-vec-of-bool)
+ * [How do I connect a subset of Bundle fields?](#how-do-i-connect-a-subset-of-bundle-fields)
+* Vectors and Registers
+ * [Can I make a 2D or 3D Vector?](#can-i-make-a-2D-or-3D-Vector)
+ * [How do I create a Vector of Registers?](#how-do-i-create-a-vector-of-registers)
+ * [How do I create a Reg of type Vec?](#how-do-i-create-a-reg-of-type-vec)
+* [How do I create a finite state machine?](#how-do-i-create-a-finite-state-machine-fsm)
+* [How do I unpack a value ("reverse concatenation") like in Verilog?](#how-do-i-unpack-a-value-reverse-concatenation-like-in-verilog)
+* [How do I do subword assignment (assign to some bits in a UInt)?](#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint)
+* [How do I create an optional I/O?](#how-do-i-create-an-optional-io)
+* Predictable Naming
+ * [How do I get Chisel to name signals properly in blocks like when/withClockAndReset?](#how-do-i-get-chisel-to-name-signals-properly-in-blocks-like-whenwithclockandreset)
+ * [How do I get Chisel to name the results of vector reads properly?](#how-do-i-get-chisel-to-name-the-results-of-vector-reads-properly)
+ * [How can I dynamically set/parametrize the name of a module?](#how-can-i-dynamically-setparametrize-the-name-of-a-module)
+* Directionality
+ * [How do I strip directions from a bidirectional Bundle (or other Data)?](#how-do-i-strip-directions-from-a-bidirectional-bundle-or-other-data)
+
+## Type Conversions
+
+### How do I create a UInt from an instance of a Bundle?
+
+Call [`asUInt`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html#asUInt():chisel3.UInt) on the [`Bundle`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html) instance.
+
+```scala mdoc:silent:reset
+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
+ printf(p"$uint") // 195
+
+ // Test
+ assert(uint === 0xc3.U)
+}
+```
+
+### How do I create a Bundle from a UInt?
+
+Use the [`asTypeOf`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asTypeOf[T%3C:chisel3.Data](that:T):T) method to reinterpret the [`UInt`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html) as the type of the [`Bundle`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html).
+
+```scala mdoc:silent:reset
+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)
+
+ printf(p"$bundle") // Bundle(foo -> 11, bar -> 4)
+
+ // Test
+ assert(bundle.foo === 0xb.U)
+ assert(bundle.bar === 0x4.U)
+}
+```
+
+### 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`:
+
+```scala mdoc:silent:reset
+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`](https://www.chisel-lang.org/api/latest/chisel3/VecInit$.html) given a `Seq[Bool]` generated using the [`asBools`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asBools():Seq[chisel3.Bool]) method.
+
+```scala mdoc:silent:reset
+import chisel3._
+
+class Foo extends RawModule {
+ val uint = 0xc.U
+ val vec = VecInit(uint.asBools)
+
+ printf(p"$vec") // Vec(0, 0, 1, 1)
+
+ // Test
+ assert(vec(0) === false.B)
+ assert(vec(1) === false.B)
+ assert(vec(2) === true.B)
+ assert(vec(3) === true.B)
+}
+```
+
+### How do I create a UInt from a Vec of Bool?
+
+Use the builtin function [`asUInt`](https://www.chisel-lang.org/api/latest/chisel3/Vec.html#asUInt():chisel3.UInt)
+
+```scala mdoc:silent:reset
+import chisel3._
+
+class Foo extends RawModule {
+ val vec = VecInit(true.B, false.B, true.B, true.B)
+ val uint = vec.asUInt
+
+ printf(p"$uint") // 13
+
+ // Test
+ // (remember leftmost Bool in Vec is low order bit)
+ assert(0xd.U === uint)
+
+}
+```
+
+### How do I connect a subset of Bundle fields?
+
+See the [DataView cookbook](dataview#how-do-i-connect-a-subset-of-bundle-fields).
+
+## Vectors and Registers
+
+### Can I make a 2D or 3D Vector?
+
+Yes. Using `VecInit` you can make Vectors that hold Vectors of Chisel types. Methods `fill` and `tabulate` make these multi-dimensional Vectors.
+
+```scala mdoc:silent:reset
+import chisel3._
+
+class MyBundle extends Bundle {
+ val foo = UInt(4.W)
+ val bar = UInt(4.W)
+}
+
+class Foo extends Module {
+ //2D Fill
+ val twoDVec = VecInit.fill(2, 3)(5.U)
+ //3D Fill
+ val myBundle = Wire(new MyBundle)
+ myBundle.foo := 0xc.U
+ myBundle.bar := 0x3.U
+ val threeDVec = VecInit.fill(1, 2, 3)(myBundle)
+ assert(threeDVec(0)(0)(0).foo === 0xc.U && threeDVec(0)(0)(0).bar === 0x3.U)
+
+ //2D Tabulate
+ val indexTiedVec = VecInit.tabulate(2, 2){ (x, y) => (x + y).U }
+ assert(indexTiedVec(0)(0) === 0.U)
+ assert(indexTiedVec(0)(1) === 1.U)
+ assert(indexTiedVec(1)(0) === 1.U)
+ assert(indexTiedVec(1)(1) === 2.U)
+ //3D Tabulate
+ val indexTiedVec3D = VecInit.tabulate(2, 3, 4){ (x, y, z) => (x + y * z).U }
+ assert(indexTiedVec3D(0)(0)(0) === 0.U)
+ assert(indexTiedVec3D(1)(1)(1) === 2.U)
+ assert(indexTiedVec3D(1)(1)(2) === 3.U)
+ assert(indexTiedVec3D(1)(1)(3) === 4.U)
+ assert(indexTiedVec3D(1)(2)(3) === 7.U)
+}
+```
+```scala mdoc:invisible
+// Hidden but will make sure this actually compiles
+import chisel3.stage.ChiselStage
+
+ChiselStage.emitVerilog(new Foo)
+```
+
+
+### How do I create a Vector of Registers?
+
+**Rule! Use Reg of Vec not Vec of Reg!**
+
+You create a [Reg of type Vec](#how-do-i-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`](https://www.chisel-lang.org/api/latest/chisel3/Vec.html) provides more information.
+
+```scala mdoc:silent:reset
+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`](https://www.chisel-lang.org/api/latest/chisel3/experimental/index.html#ChiselEnum=chisel3.experimental.EnumFactory) to construct enumerated types representing the state of the FSM.
+State transitions are then handled with [`switch`](https://www.chisel-lang.org/api/latest/chisel3/util/switch$.html)/[`is`](https://www.chisel-lang.org/api/latest/chisel3/util/is$.html) and [`when`](https://www.chisel-lang.org/api/latest/chisel3/when$.html)/[`.elsewhen`](https://www.chisel-lang.org/api/latest/chisel3/WhenContext.html#elsewhen(elseCond:=%3Echisel3.Bool)(block:=%3EUnit)(implicitsourceInfo:chisel3.internal.sourceinfo.SourceInfo,implicitcompileOptions:chisel3.CompileOptions):chisel3.WhenContext)/[`.otherwise`](https://www.chisel-lang.org/api/latest/chisel3/WhenContext.html#otherwise(block:=%3EUnit)(implicitsourceInfo:chisel3.internal.sourceinfo.SourceInfo,implicitcompileOptions:chisel3.CompileOptions):Unit).
+
+```scala mdoc:silent:reset
+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`:
+
+```verilog
+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:
+
+```scala mdoc:silent:reset
+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:
+
+```scala mdoc:silent
+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](https://github.com/freechipsproject/rocket-chip/blob/723af5e6b69e07b5f94c46269a208a8d65e9d73b/src/main/scala/util/Misc.scala#L140) 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.
+
+```scala mdoc:silent:reset
+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.
+```scala mdoc:crash
+(new ChiselStage).execute(Array("-X", "verilog"), Seq(new ChiselGeneratorAnnotation(() => new Foo)))
+```
+
+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:
+
+```scala mdoc:silent:reset
+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`.
+
+```scala mdoc:silent:reset
+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 where an entire `IO` is optional:
+
+```scala mdoc:silent:reset
+import chisel3._
+
+class ModuleWithOptionalIO(flag: Boolean) extends Module {
+ 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?
+
+Use the compiler plugin, and check out the [Naming Cookbook](#naming) if that still does not do what you want.
+
+### How do I get Chisel to name the results of vector reads properly?
+Currently, name information is lost when using dynamic indexing. For example:
+```scala mdoc:silent
+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).
+```verilog
+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:
+```scala
+val x = WireInit(io.in(io.idx))
+```
+
+Which produces:
+```verilog
+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 `BlackBox`es. Example:
+
+```scala mdoc:silent:reset
+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 "desired names" for `Salt` and `Coffee` in the output Verilog:
+```scala mdoc:silent
+import chisel3.stage.ChiselStage
+
+ChiselStage.emitVerilog(new Salt)
+```
+
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new Salt)
+```
+
+## Directionality
+
+### How do I strip directions from a bidirectional Bundle (or other Data)?
+
+Given a bidirectional port like a `Decoupled`, you will get an error if you try to connect it directly
+to a register:
+
+```scala mdoc:silent
+import chisel3.util.Decoupled
+class BadRegConnect extends Module {
+ val io = IO(new Bundle {
+ val enq = Decoupled(UInt(8.W))
+ })
+
+ val monitor = Reg(chiselTypeOf(io.enq))
+ monitor := io.enq
+}
+```
+
+```scala mdoc:crash
+ChiselStage.emitVerilog(new BadRegConnect)
+```
+
+While there is no construct to "strip direction" in Chisel3, wrapping a type in `Output(...)`
+(the default direction in Chisel3) will
+set all of the individual elements to output direction.
+This will have the desired result when used to construct a Register:
+
+```scala mdoc:silent
+import chisel3.util.Decoupled
+class CoercedRegConnect extends Module {
+ val io = IO(new Bundle {
+ val enq = Flipped(Decoupled(UInt(8.W)))
+ })
+
+ // Make a Reg which contains all of the bundle's signals, regardless of their directionality
+ val monitor = Reg(Output(chiselTypeOf(io.enq)))
+ // Even though io.enq is bidirectional, := will drive all fields of monitor with the fields of io.enq
+ monitor := io.enq
+}
+```
+
+<!-- Just make sure it actually works -->
+```scala mdoc:invisible
+ChiselStage.emitVerilog(new CoercedRegConnect {
+ // Provide default connections that would just muddy the example
+ io.enq.ready := true.B
+ // dontTouch so that it shows up in the Verilog
+ dontTouch(monitor)
+})
+```
diff --git a/docs/src/cookbooks/cookbooks.md b/docs/src/cookbooks/cookbooks.md
new file mode 100644
index 00000000..ee6f5e45
--- /dev/null
+++ b/docs/src/cookbooks/cookbooks.md
@@ -0,0 +1,15 @@
+---
+layout: docs
+title: "Cookbooks"
+section: "chisel3"
+---
+
+# Cookbooks
+
+Welcome to the Chisel Cookbooks, where we capture frequently-used design patterns or troubleshooting questions.
+If you have any requests or examples to share,
+please [file an issue](https://github.com/chipsalliance/chisel3/issues/new) and let us know!
+
+* [General Cookbooks](cookbook)
+* [Naming Cookbook](naming)
+* [Troubleshooting Guide](troubleshooting)
diff --git a/docs/src/cookbooks/dataview.md b/docs/src/cookbooks/dataview.md
new file mode 100644
index 00000000..ed969ca1
--- /dev/null
+++ b/docs/src/cookbooks/dataview.md
@@ -0,0 +1,179 @@
+---
+layout: docs
+title: "DataView Cookbook"
+section: "chisel3"
+---
+
+# DataView Cookbook
+
+* [How do I view a Data as a UInt or vice versa?](#how-do-i-view-a-data-as-a-uint-or-vice-versa)
+* [How do I create a DataView for a Bundle has a type parameter?](#how-do-i-create-a-dataview-for-a-bundle-has-a-type-parameter)
+* [How do I create a DataView for a Bundle with optional fields?](#how-do-i-create-a-dataview-for-a-bundle-with-optional-fields)
+* [How do I connect a subset of Bundle fields?](#how-do-i-connect-a-subset-of-bundle-fields)
+ * [How do I view a Bundle as a parent type (superclass)?](#how-do-i-view-a-bundle-as-a-parent-type-superclass)
+ * [How do I view a Bundle as a parent type when the parent type is abstract (like a trait)?](#how-do-i-view-a-bundle-as-a-parent-type-when-the-parent-type-is-abstract-like-a-trait)
+
+## How do I view a Data as a UInt or vice versa?
+
+Subword viewing (using concatenations or bit extractions in `DataViews`) is not yet supported.
+We intend to implement this in the future, but for the time being, use regular casts
+(`.asUInt` and `.asTypeOf`).
+
+## How do I create a DataView for a Bundle has a type parameter?
+
+Instead of using a `val`, use a `def` which can have type parameters:
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.dataview._
+
+class Foo[T <: Data](val foo: T) extends Bundle
+class Bar[T <: Data](val bar: T) extends Bundle
+
+object Foo {
+ implicit def view[T <: Data]: DataView[Foo[T], Bar[T]] = {
+ DataView(f => new Bar(f.foo.cloneType), _.foo -> _.bar)
+ // .cloneType is necessary because the f passed to this function will be bound hardware
+ }
+}
+```
+
+```scala mdoc:invisible
+// Make sure this works during elaboration, not part of doc
+class MyModule extends RawModule {
+ val in = IO(Input(new Foo(UInt(8.W))))
+ val out = IO(Output(new Bar(UInt(8.W))))
+ out := in.viewAs[Bar[UInt]]
+}
+chisel3.stage.ChiselStage.emitVerilog(new MyModule)
+```
+If you think about type parameterized classes as really being a family of different classes
+(one for each type parameter), you can think about the `implicit def` as a generator of `DataViews`
+for each type parameter.
+
+## How do I create a DataView for a Bundle with optional fields?
+
+Instead of using the default `DataView` apply method, use `DataView.mapping`:
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.dataview._
+
+class Foo(val w: Option[Int]) extends Bundle {
+ val foo = UInt(8.W)
+ val opt = w.map(x => UInt(x.W))
+}
+class Bar(val w: Option[Int]) extends Bundle {
+ val bar = UInt(8.W)
+ val opt = w.map(x => UInt(x.W))
+}
+
+object Foo {
+ implicit val view: DataView[Foo, Bar] =
+ DataView.mapping(
+ // First argument is always the function to make the view from the target
+ f => new Bar(f.w),
+ // Now instead of a varargs of tuples of individual mappings, we have a single function that
+ // takes a target and a view and returns an Iterable of tuple
+ (f, b) => List(f.foo -> b.bar) ++ f.opt.map(_ -> b.opt.get)
+ // ^ Note that we can append options since they are Iterable!
+
+ )
+}
+```
+
+```scala mdoc:invisible
+// Make sure this works during elaboration, not part of doc
+class MyModule extends RawModule {
+ val in = IO(Input(new Foo(Some(8))))
+ val out = IO(Output(new Bar(Some(8))))
+ out := in.viewAs[Bar]
+}
+chisel3.stage.ChiselStage.emitVerilog(new MyModule)
+```
+
+## How do I connect a subset of Bundle fields?
+
+Chisel 3 requires types to match exactly for connections.
+DataView provides a mechanism for "viewing" one `Bundle` object as if it were the type of another,
+which allows them to be connected.
+
+### How do I view a Bundle as a parent type (superclass)?
+
+For viewing `Bundles` as the type of the parent, it is as simple as using `viewAsSupertype` and providing a
+template object of the parent type:
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.dataview._
+
+class Foo extends Bundle {
+ val foo = UInt(8.W)
+}
+class Bar extends Foo {
+ val bar = UInt(8.W)
+}
+class MyModule extends Module {
+ val foo = IO(Input(new Foo))
+ val bar = IO(Output(new Bar))
+ bar.viewAsSupertype(new Foo) := foo // bar.foo := foo.foo
+ bar.bar := 123.U // all fields need to be connected
+}
+```
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new MyModule)
+```
+
+### How do I view a Bundle as a parent type when the parent type is abstract (like a trait)?
+
+Given the following `Bundles` that share a common `trait`:
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.dataview._
+
+trait Super extends Bundle {
+ def bitwidth: Int
+ val a = UInt(bitwidth.W)
+}
+class Foo(val bitwidth: Int) extends Super {
+ val foo = UInt(8.W)
+}
+class Bar(val bitwidth: Int) extends Super {
+ val bar = UInt(8.W)
+}
+```
+
+`Foo` and `Bar` cannot be connected directly, but they could be connected by viewing them both as if
+they were instances of their common supertype, `Super`.
+A straightforward approach might run into an issue like the following:
+
+```scala mdoc:fail
+class MyModule extends Module {
+ val foo = IO(Input(new Foo(8)))
+ val bar = IO(Output(new Bar(8)))
+ bar.viewAsSupertype(new Super) := foo.viewAsSupertype(new Super)
+}
+```
+
+The problem is that `viewAs` requires an object to use as a type template (so that it can be cloned),
+but `traits` are abstract and cannot be instantiated.
+The solution is to create an instance of an _anonymous class_ and use that object as the argument to `viewAs`.
+We can do this like so:
+
+```scala mdoc:silent
+class MyModule extends Module {
+ val foo = IO(Input(new Foo(8)))
+ val bar = IO(Output(new Bar(8)))
+ val tpe = new Super { // Adding curly braces creates an anonymous class
+ def bitwidth = 8 // We must implement any abstract methods
+ }
+ bar.viewAsSupertype(tpe) := foo.viewAsSupertype(tpe)
+}
+```
+By adding curly braces after the name of the trait, we're telling Scala to create a new concrete
+subclass of the trait, and create an instance of it.
+As indicated in the comment, abstract methods must still be implemented.
+This is the same that happens when one writes `new Bundle {}`,
+the curly braces create a new concrete subclass; however, because `Bundle` has no abstract methods,
+the contents of the body can be empty.
diff --git a/docs/src/cookbooks/hierarchy.md b/docs/src/cookbooks/hierarchy.md
new file mode 100644
index 00000000..91d99aa6
--- /dev/null
+++ b/docs/src/cookbooks/hierarchy.md
@@ -0,0 +1,204 @@
+---
+layout: docs
+title: "Hierarchy Cookbook"
+section: "chisel3"
+---
+
+# Hierarchy Cookbook
+
+* [How do I instantiate multiple instances with the same module parameterization, but avoid re-elaboration?](#how-do-i-instantiate-multiple-instances-with-the-same-module-parameterization)
+* [How do I access internal fields of an instance?](#how-do-i-access-internal-fields-of-an-instance)
+* [How do I make my parameters accessable from an instance?](#how-do-i-make-my-parameters-accessable-from-an-instance)
+* [How do I reuse a previously elaborated module, if my new module has the same parameterization?](#how-do-i-reuse-a-previously-elaborated-module-if-my-new-module-has-the-same-parameterization)
+
+## How do I instantiate multiple instances with the same module parameterization?
+
+Prior to this package, Chisel users relied on deduplication in a FIRRTL compiler to combine
+structurally equivalent modules into one module (aka "deduplication").
+This package introduces the following new APIs to enable multiply-instantiated modules directly in Chisel.
+
+`Definition(...)` enables elaborating a module, but does not actually instantiate that module.
+Instead, it returns a `Definition` class which represents that module's definition.
+
+`Instance(...)` takes a `Definition` and instantiates it, returning an `Instance` object.
+
+Modules (classes or traits) which will be used with the `Definition`/`Instance` api should be marked
+with the `@instantiable` annotation at the class/trait definition.
+
+To make a Module's members variables accessible from an `Instance` object, they must be annotated
+with the `@public` annotation. Note that this is only accessible from a Scala sense—this is not
+in and of itself a mechanism for cross-module references.
+
+In the following example, use `Definition`, `Instance`, `@instantiable` and `@public` to create
+multiple instances of one specific parameterization of a module, `AddOne`.
+
+```scala mdoc:silent
+import chisel3._
+import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public}
+
+@instantiable
+class AddOne(width: Int) extends Module {
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ out := in + 1.U
+}
+
+class AddTwo(width: Int) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+ val addOneDef = Definition(new AddOne(width))
+ val i0 = Instance(addOneDef)
+ val i1 = Instance(addOneDef)
+ i0.in := in
+ i1.in := i0.out
+ out := i1.out
+}
+```
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new AddTwo(10))
+```
+
+## How do I access internal fields of an instance?
+
+You can mark internal members of a class or trait marked with `@instantiable` with the `@public` annotation.
+The requirements are that the field is publicly accessible, is a `val` or `lazy val`, and is a valid type.
+The list of valid types are:
+
+1. `IsInstantiable`
+2. `IsLookupable`
+3. `Data`
+4. `BaseModule`
+5. `Iterable`/`Option `containing a type that meets these requirements
+6. Basic type like `String`, `Int`, `BigInt` etc.
+
+To mark a superclass's member as `@public`, use the following pattern (shown with `val clock`).
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.hierarchy.{instantiable, public}
+
+@instantiable
+class MyModule extends Module {
+ @public val clock = clock
+}
+```
+
+You'll get the following error message for improperly marking something as `@public`:
+
+```scala mdoc:reset:fail
+import chisel3._
+import chisel3.experimental.hierarchy.{instantiable, public}
+
+object NotValidType
+
+@instantiable
+class MyModule extends Module {
+ @public val x = NotValidType
+}
+```
+
+## How do I make my parameters accessible from an instance?
+
+If an instance's parameters are simple (e.g. `Int`, `String` etc.) they can be marked directly with `@public`.
+
+Often, parameters are more complicated and are contained in case classes.
+In such cases, mark the case class with the `IsLookupable` trait.
+This indicates to Chisel that instances of the `IsLookupable` class may be accessed from within instances.
+
+However, ensure that these parameters are true for **all** instances of a definition.
+For example, if our parameters contained an id field which was instance-specific but defaulted to zero,
+then the definition's id would be returned for all instances.
+This change in behavior could lead to bugs if other code presumed the id field was correct.
+
+Thus, it is important that when converting normal modules to use this package,
+you are careful about what you mark as `IsLookupable`.
+
+In the following example, we added the trait `IsLookupable` to allow the member to be marked `@public`.
+
+```scala mdoc:reset:silent
+import chisel3._
+import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, IsLookupable, public}
+
+case class MyCaseClass(width: Int) extends IsLookupable
+
+@instantiable
+class MyModule extends Module {
+ @public val x = MyCaseClass(10)
+}
+
+class Top extends Module {
+ val inst = Instance(Definition(new MyModule))
+ println(s"Width is ${inst.x.width}")
+}
+```
+```scala mdoc:passthrough
+println("```")
+chisel3.stage.ChiselStage.elaborate(new Top)
+println("```")
+```
+
+## How do I look up parameters from a Definition, if I don't want to instantiate it?
+
+Just like `Instance`s, `Definition`'s also contain accessors for `@public` members.
+As such, you can directly access them:
+
+```scala mdoc:reset:silent
+import chisel3._
+import chisel3.experimental.hierarchy.{Definition, instantiable, public}
+
+@instantiable
+class AddOne(val width: Int) extends Module {
+ @public val width = width
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ out := in + 1.U
+}
+
+class Top extends Module {
+ val definition = Definition(new AddOne(10))
+ println(s"Width is: ${definition.width}")
+}
+```
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new Top())
+```
+
+## How do I parameterize a module by its children instances?
+
+Prior to the introduction of this package, a parent module would have to pass all necessary parameters
+when instantiating a child module.
+This had the unfortunate consequence of requiring a parent's parameters to always contain the child's
+parameters, which was an unnecessary coupling which lead to some anti-patterns.
+
+Now, a parent can take a child `Definition` as an argument, and instantiate it directly.
+In addition, it can analyze the parameters used in the definition to parameterize itself.
+In a sense, now the child can actually parameterize the parent.
+
+In the following example, we create a definition of `AddOne`, and pass the definition to `AddTwo`.
+The width of the `AddTwo` ports are now derived from the parameterization of the `AddOne` instance.
+
+```scala mdoc:reset
+import chisel3._
+import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public}
+
+@instantiable
+class AddOne(val width: Int) extends Module {
+ @public val width = width
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ out := in + 1.U
+}
+
+class AddTwo(addOneDef: Definition[AddOne]) extends Module {
+ val i0 = Instance(addOneDef)
+ val i1 = Instance(addOneDef)
+ val in = IO(Input(UInt(addOneDef.width.W)))
+ val out = IO(Output(UInt(addOneDef.width.W)))
+ i0.in := in
+ i1.in := i0.out
+ out := i1.out
+}
+```
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new AddTwo(Definition(new AddOne(10))))
+```
diff --git a/docs/src/cookbooks/troubleshooting.md b/docs/src/cookbooks/troubleshooting.md
new file mode 100644
index 00000000..f8a0cec1
--- /dev/null
+++ b/docs/src/cookbooks/troubleshooting.md
@@ -0,0 +1,64 @@
+---
+layout: docs
+title: "Troubleshooting"
+section: "chisel3"
+---
+
+# Troubleshooting
+
+
+This page is a starting point for recording common and not so common problems in developing with Chisel3. In particular, those situations where there is a work around that will keep you going.
+
+### `type mismatch` specifying width/value of a `UInt`/`SInt`
+
+*I have some old code that used to work correctly in chisel2 (and still does if I use the `import Chisel._` compatibility layer)
+but causes a `type mismatch` error in straight chisel3:*
+
+```scala mdoc:silent:fail
+class TestBlock extends Module {
+ val io = IO(new Bundle {
+ val output = Output(UInt(width=3))
+ })
+}
+```
+*produces*
+```bash
+type mismatch;
+[error] found : Int(3)
+[error] required: chisel3.internal.firrtl.Width
+[error] val output = Output(UInt(width=3))
+```
+
+The single argument, multi-function object/constructors from chisel2 have been removed from chisel3.
+It was felt these were too prone to error and made it difficult to diagnose error conditions in chisel3 code.
+
+In chisel3, the single argument to the `UInt`/`SInt` object/constructor specifies the *width* and must be a `Width` type.
+Although there are no automatic conversions from `Int` to `Width`, an `Int` may be converted to a `Width` by applying the `W` method to an `Int`.
+In chisel3, the above code becomes:
+```scala mdoc:silent
+import chisel3._
+
+class TestBlock extends Module {
+ val io = IO(new Bundle {
+ val output = Output(UInt(3.W))
+ })
+}
+```
+`UInt`/`SInt` literals may be created from an `Int` with the application of either the `U` or `S` method.
+
+```scala mdoc:fail
+UInt(42)
+```
+
+in chisel2, becomes
+```scala mdoc:silent
+42.U
+```
+in chisel3
+
+A literal with a specific width is created by calling the `U` or `S` method with a `W` argument.
+Use:
+```scala mdoc:silent
+1.S(8.W)
+```
+to create an 8-bit wide (signed) literal with value 1.