From f1ad5b58e8a749d558758288d03ce75bf6b8ff9c Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Thu, 18 Mar 2021 16:47:58 -0700 Subject: Reorganize website docs (#1806) Updates to chisel3 documentation for website: * guard code examples with mdoc and fix errors encountered along the way * move some website content here vs splitting the content across two repos * Bring in the interval-types and loading memories content so that it will be visible from the website * remove all references to the wiki (deprecated) * Remove reference to Wiki from the README * fix tabbing and compile of chisel3-vs-chisel2 section * Appendix: faqs now guarded and compile * FAQs: move to resources section--- docs/src/cookbooks/cookbook.md | 471 ++++++++++++++++++++++++++++++++++ docs/src/cookbooks/cookbooks.md | 15 ++ docs/src/cookbooks/troubleshooting.md | 64 +++++ 3 files changed, 550 insertions(+) create mode 100644 docs/src/cookbooks/cookbook.md create mode 100644 docs/src/cookbooks/cookbooks.md create mode 100644 docs/src/cookbooks/troubleshooting.md (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md new file mode 100644 index 00000000..6a8eeebf --- /dev/null +++ b/docs/src/cookbooks/cookbook.md @@ -0,0 +1,471 @@ +--- +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). + +* Converting Chisel Types to/from UInt + * [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 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) +* Vectors and Registers + * [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) + +## Converting Chisel Types to/from UInt + +### 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 +} +``` + +### 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) +} +``` + +### 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) +} +``` + +### 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 +} +``` + +## 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](#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? + +To get Chisel to name signals (wires and registers) declared inside of blocks like `when`, `withClockAndReset`, etc, use the [`@chiselName`](https://www.chisel-lang.org/api/latest/chisel3/experimental/package$$chiselName.html) annotation as shown below: + +```scala mdoc:silent:reset +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. + +```scala +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`): + +```scala mdoc:passthrough +import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} +import firrtl.annotations.DeletedAnnotation +import firrtl.EmittedVerilogCircuitAnnotation + +class TestModWithout extends Module { + override val desiredName = "TestMod" + 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 + } +} + +(new ChiselStage) + .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestModWithout))) + .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } + .foreach(a => println(s"""|```verilog + |$a + |```""".stripMargin)) +``` + +However, if we use `@chiselName` then the register previously called `_T` is now `innerReg`: +```scala mdoc:passthrough +(new ChiselStage) + .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestMod))) + .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } + .foreach(a => println(s"""|```verilog + |$a + |```""".stripMargin)) +``` +### 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 "desire name" for `Salt` and `Coffee` in the output Verilog: +```scala mdoc:passthrough +import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} +import firrtl.annotations.DeletedAnnotation +import firrtl.EmittedVerilogCircuitAnnotation + +(new ChiselStage) + .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new Salt))) + .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } + .foreach(a => println(s"""|```verilog + |$a + |```""".stripMargin)) +``` 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/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. -- cgit v1.2.3 From 6e22d91ed31206292f9f8b02a89fe18885ad602d Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Mon, 12 Apr 2021 11:19:20 -0700 Subject: Add "how to tie off to 0" to the Cookbook (#1857) --- docs/src/cookbooks/cookbook.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index 6a8eeebf..b85ceadc 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -12,6 +12,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * Converting Chisel Types to/from UInt * [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) * Vectors and Registers @@ -66,6 +67,36 @@ class Foo extends RawModule { } ``` +### 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. -- cgit v1.2.3 From 23b3fe8a6a2db92599bb0775626425056d47d1de Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Mon, 26 Apr 2021 16:02:54 -0700 Subject: Cookbooks: make examples more clear and remove naming (#1881) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- docs/src/cookbooks/cookbook.md | 92 ++++++++++++------------------------------ 1 file changed, 26 insertions(+), 66 deletions(-) (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index b85ceadc..290a6c82 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -46,6 +46,10 @@ class Foo extends RawModule { bundle.foo := 0xc.U bundle.bar := 0x3.U val uint = bundle.asUInt + printf(p"$uint") // 195 + + // Test + assert(uint === 0xc3.U) } ``` @@ -64,6 +68,12 @@ class MyBundle extends Bundle { 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) } ``` @@ -107,6 +117,14 @@ 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) } ``` @@ -120,6 +138,13 @@ 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) + } ``` @@ -331,73 +356,8 @@ class ModuleWithOptionalIO(flag: Boolean) extends Module { ### 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`](https://www.chisel-lang.org/api/latest/chisel3/experimental/package$$chiselName.html) annotation as shown below: - -```scala mdoc:silent:reset -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. - -```scala -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`): - -```scala mdoc:passthrough -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.annotations.DeletedAnnotation -import firrtl.EmittedVerilogCircuitAnnotation - -class TestModWithout extends Module { - override val desiredName = "TestMod" - 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 - } -} +Use the compiler plugin, and check out the [Naming Cookbook](#naming) if that still does not do what you want. -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestModWithout))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` - -However, if we use `@chiselName` then the register previously called `_T` is now `innerReg`: -```scala mdoc:passthrough -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestMod))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` ### 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 -- cgit v1.2.3 From 9fdea534f83578f745ec22cc7e530105f9fd67f7 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Wed, 28 Apr 2021 10:57:13 -0700 Subject: Cookbook: clean up desiredName example (#1886) * Cookbook: clean up desiredName example * Update cookbook.md--- docs/src/cookbooks/cookbook.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index 290a6c82..1b47ad14 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -447,16 +447,13 @@ class Salt extends Module { } ``` -Elaborating the Chisel module `Salt` yields our "desire name" for `Salt` and `Coffee` in the output Verilog: -```scala mdoc:passthrough -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.annotations.DeletedAnnotation -import firrtl.EmittedVerilogCircuitAnnotation - -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new Salt))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) +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) ``` -- cgit v1.2.3 From 1ceb974c55c6785c21ab3934fa750ade0702e276 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 12 Aug 2021 17:04:11 -0700 Subject: Add DataView (#1955) DataView is a mechanism for "viewing" Scala objects as a subtype of `Data`. Often, this is useful for viewing one subtype of `Data`, as another. One can think about a DataView as a cross between a customizable cast and an untagged union. A DataView has a Target type `T`, and a View type `V`. DataView requires that an implementation of `DataProduct` is available for Target types. DataProduct is a type class that provides a way to iterate on `Data` children of objects of implementing types. If a DataView is provided for a type T to a type V, then the function .viewAs[V] (of type T => V) is available. The object (of type T) returned by .viewAs is called a "View" and can be used as both an rvalue and an lvalue. Unlike when using an .asTypeOf cast, connecting to a "View" will connect to the associated field or fields of the underlying Target. DataView also enables .viewAsSupertype which is available for viewing Bundles as a parent Bundle type. It is similar to .viewAs but requires a prototype object of the Target type which will be cloned in order to create the returned View. .viewAsSupertype maps between the corresponding fields of the parent and child Bundle types.--- docs/src/cookbooks/cookbook.md | 9 ++- docs/src/cookbooks/dataview.md | 179 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 docs/src/cookbooks/dataview.md (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index 1b47ad14..f033c285 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -9,12 +9,13 @@ section: "chisel3" Please note that these examples make use of [Chisel's scala-style printing](../explanations/printing#scala-style). -* Converting Chisel Types to/from UInt +* 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 * [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) @@ -27,7 +28,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * [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) -## Converting Chisel Types to/from UInt +## Type Conversions ### How do I create a UInt from an instance of a Bundle? @@ -148,6 +149,10 @@ class Foo extends RawModule { } ``` +### 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 ### How do I create a Vector of Registers? 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. -- cgit v1.2.3 From e14bcb145860207a825f780e3d0984e869f605c9 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 17 Aug 2021 14:24:20 -0700 Subject: [docs] Add example of stripping directions from type (#2074) * [docs] Add example of stripping directions from type * Apply suggestions from code review Co-authored-by: Megan Wachs * Improve := comment Co-authored-by: Megan Wachs Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- docs/src/cookbooks/cookbook.md | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index f033c285..cff7a5b2 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -27,6 +27,8 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * [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 @@ -462,3 +464,55 @@ 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 +} +``` + + +```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) +}) +``` -- cgit v1.2.3 From f50ce19406e45982390162777fb62c8563c962c7 Mon Sep 17 00:00:00 2001 From: anniej-sifive Date: Mon, 23 Aug 2021 14:37:09 -0700 Subject: Add multiple dimensions to VecInit fill and iterate (#2065) Co-authored-by: Jack Koenig --- docs/src/cookbooks/cookbook.md | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'docs/src/cookbooks') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index cff7a5b2..ce49b668 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -17,6 +17,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * [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) @@ -157,6 +158,51 @@ 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!** -- cgit v1.2.3 From 9fa8da227569455a77596355aeb114f9c164510a Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Sun, 5 Sep 2021 12:11:32 -0700 Subject: Add Definition and Instance API (#2045) This introduces a new experimental API for module instantiation that disentagles elaborating the definition (or implementation) from instantiation of a given module. This solves Chisel's longstanding reliance on "Deduplication" for generating Verilog with multiple instances of the same module. The new API resides in package chisel3.experimental.hierarchy. Please see the hierarchy ScalaDoc, documentation, and tests for examples of use. Co-authored-by: Jack Koenig Co-authored-by: Megan Wachs Co-authored-by: Schuyler Eldridge --- docs/src/cookbooks/hierarchy.md | 204 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/src/cookbooks/hierarchy.md (limited to 'docs/src/cookbooks') 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)))) +``` -- cgit v1.2.3