From d001b34f816f1f65d0625aebf33e5cfc5ba93e49 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Thu, 16 Jun 2022 23:15:42 +0000 Subject: Define leading '_' as API for creating temporaries (backport #2580) (#2581) * Define leading '_' as API for creating temporaries Chisel and FIRRTL have long used signals with names beginning with an underscore as an API to specify that the name does not really matter. Tools like Verilator follow a similar convention and exclude signals with underscore names from waveform dumps by default. With the introduction of compiler-plugin prefixing in Chisel 3.4, the convention remained but was hard for users to use unless the unnnamed signal existed outside of any prefix domain. Notably, unnamed signals are most useful when creating wires inside of utility methods which almost always results in the signal ending up with a prefix. With this commit, Chisel explicitly recognizes signals whos val names start with an underscore and preserve that underscore regardless of any prefixing. Chisel will also ignore such underscores when generating prefixes based on the temporary signal, preventing accidental double underscores in the names of signals that are prefixed by the temporary. (cherry picked from commit bd94366290886f3489d58f88b9768c7c11fa2cb6) * Remove unused defaultPrefix argument from _computeName (cherry picked from commit ec178aa20a830df2c8c756b9e569709a59073554) # Conflicts: # core/src/main/scala/chisel3/Module.scala # core/src/main/scala/chisel3/experimental/hierarchy/ModuleClone.scala * Resolve backport conflicts * Waive false positive binary compatibility errors Co-authored-by: Jack Koenig --- docs/src/explanations/naming.md | 121 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 4 deletions(-) (limited to 'docs/src/explanations') diff --git a/docs/src/explanations/naming.md b/docs/src/explanations/naming.md index a9f21936..99797cb2 100644 --- a/docs/src/explanations/naming.md +++ b/docs/src/explanations/naming.md @@ -24,11 +24,11 @@ import chisel3.experimental.{prefix, noPrefix} import chisel3.stage.ChiselStage ``` -With the release of Chisel 3.4, users should add the following line to their build.sbt settings to get the improved -naming: +With the release of Chisel 3.5, users are required to add the following line to +their build.sbt settings: ```scala -// chiselVersion is the String version (eg. "3.4.0") +// chiselVersion is the String version (eg. "3.5.3") addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full) ``` @@ -78,6 +78,29 @@ class Example2 extends Module { ChiselStage.emitVerilog(new Example2) ``` +Prefixing can also be derived from the name of signals on the left-hand side of a connection. +While this is not implemented via the compiler plugin, the behavior should feel similar: + +```scala mdoc +class ConnectPrefixing extends Module { + val in = IO(Input(UInt(2.W))) + // val in = autoNameRecursively("in")(prefix("in")(IO(Input(UInt(2.W))))) + + val out = IO(Output(UInt(2.W))) + // val out = autoNameRecursively("out")(prefix("out")(IO(Output(UInt(2.W))))) + + out := { // technically this is not wrapped in autoNameRecursively nor prefix + // But the Chisel runtime will still use the name of `out` as a prefix + val double = in * in + // val double = autoNameRecursively("double")(prefix("double")(in * in)) + double + 1.U + } +} +``` +```scala mdoc:verilog +ChiselStage.emitVerilog(new ConnectPrefixing) +``` + Note that the naming also works if the hardware type is nested in an `Option` or a subtype of `Iterable`: ```scala mdoc @@ -121,7 +144,7 @@ Users who desire a prefix are encouraged to provide one as [described below](#pr ### Prefixing As shown above, the compiler plugin automatically attempts to prefix some of your signals for you. However, you as a -user can also add your own prefixes. This is especially for ECO-type fixes where you need to add some logic to a module +user can also add your own prefixes. This is especially useful for ECO-type fixes where you need to add some logic to a module but don't want to influence other names in the module. In the following example, we prefix additional logic with "ECO", where `Example4` is pre-ECO and `Example5` is post-ECO: @@ -202,6 +225,96 @@ class Example8 extends Module { ChiselStage.emitVerilog(new Example8) ``` +Note that using `.suggestName` does **not** affect prefixes derived from val names; +however, it _can_ affect prefixes derived from connections (eg. `:=`): + +```scala mdoc +class ConnectionPrefixExample extends Module { + val in0 = IO(Input(UInt(2.W))) + val in1 = IO(Input(UInt(2.W))) + + val out0 = { + val port = IO(Output(UInt())) + // Even though this suggestName is before mul, the prefix used in this scope + // is derived from `val out0`, so this does not affect the name of mul + port.suggestName("foo") + // out0_mul + val mul = in0 * in1 + port := mul + 1.U + port + } + + val out1 = IO(Output(UInt())) + val out2 = IO(Output(UInt())) + + out1 := { + // out1_sum + val sum = in0 + in1 + sum + 1.U + } + // Comes after so does *not* affect prefix above + out1.suggestName("bar") + + // Comes before so *does* affect prefix below + out2.suggestName("fizz") + out2 := { + // fizz_diff + val diff = in0 - in1 + diff + 1.U + } +} +``` +```scala mdoc:verilog +ChiselStage.emitVerilog(new ConnectionPrefixExample) +``` + +As this example illustrates, this behavior is slightly inconsistent so is subject to change in a future version of Chisel. + + +### Behavior for "Unnamed signals" (aka "Temporaries") + +If you want to signify that the name of a signal does not matter, you can prefix the name of your val with `_`. +Chisel will preserve the convention of leading `_` signifying an unnamed signal across prefixes. +For example: + +```scala mdoc +class TemporaryExample extends Module { + val in0 = IO(Input(UInt(2.W))) + val in1 = IO(Input(UInt(2.W))) + + val out = { + val port = IO(Output(UInt())) + val _sum = in0 + in1 + port := _sum + 1.U + port + } +} +``` +```scala mdoc:verilog +ChiselStage.emitVerilog(new TemporaryExample) +``` + +If an unnamed signal is itself used to generate a prefix, the leading `_` will be ignored to avoid double `__` in the names of further nested signals. + + +```scala mdoc +class TemporaryPrefixExample extends Module { + val in0 = IO(Input(UInt(2.W))) + val in1 = IO(Input(UInt(2.W))) + val out = IO(Output(UInt())) + + val _sum = { + val x = in0 + in1 + x + 1.U + } + out := _sum & 0x2.U +} +``` +```scala mdoc:verilog +ChiselStage.emitVerilog(new TemporaryPrefixExample) +``` + + ### Set a Module Name If you want to specify the module's name (not the instance name of a module), you can always override the `desiredName` -- cgit v1.2.3 From a931c5e218014c659bbff7d0dec74c882281d9a0 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 27 Jun 2022 18:12:13 +0000 Subject: Fix broken link in interfaces-and-connections.md (#2607) (#2608) Links between markdown pages should not have any file extension to ensure they work on the website. (cherry picked from commit 04d4dc6da11678d0f12f84913fc05359d9a998a1) Co-authored-by: Jack Koenig --- docs/src/explanations/interfaces-and-connections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/src/explanations') diff --git a/docs/src/explanations/interfaces-and-connections.md b/docs/src/explanations/interfaces-and-connections.md index 0fb8bae8..5d9cfd3c 100644 --- a/docs/src/explanations/interfaces-and-connections.md +++ b/docs/src/explanations/interfaces-and-connections.md @@ -150,7 +150,7 @@ Below we can see the resulting error for this example: ```scala mdoc:crash ChiselStage.emitVerilog(new BlockWithTemporaryWires) ``` -For more details and information, see [Deep Dive into Connection Operators](connection-operators.md) +For more details and information, see [Deep Dive into Connection Operators](connection-operators) NOTE: When using `Chisel._` (compatibility mode) instead of `chisel3._`, the `:=` operator works in a bidirectional fashion similar to `<>`, but not exactly the same. -- cgit v1.2.3 From b8f884e15114b7c9f29b1ec8f23a4216bcbfca76 Mon Sep 17 00:00:00 2001 From: mergify[bot] Date: Mon, 25 Jul 2022 13:36:26 +0000 Subject: Add an Explanation chapter about Scala types vs Chisel Types vs Hardware (#2626) (#2642) (cherry picked from commit 81fcf229da84e334cdc466ffbb8ea74c7975a4a9) Co-authored-by: Megan Wachs --- docs/src/explanations/chisel-type-vs-scala-type.md | 285 +++++++++++++++++++++ docs/src/explanations/data-types.md | 3 +- docs/src/explanations/explanations.md | 1 + 3 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 docs/src/explanations/chisel-type-vs-scala-type.md (limited to 'docs/src/explanations') diff --git a/docs/src/explanations/chisel-type-vs-scala-type.md b/docs/src/explanations/chisel-type-vs-scala-type.md new file mode 100644 index 00000000..6c311a21 --- /dev/null +++ b/docs/src/explanations/chisel-type-vs-scala-type.md @@ -0,0 +1,285 @@ +--- +layout: docs +title: "Chisel Type vs Scala Type" +section: "chisel3" +--- + +# Chisel Type vs Scala Type + +The Scala compiler cannot distinguish between Chisel's representation of hardware such as `false.B`, `Reg(Bool())` +and pure Chisel types (e.g. `Bool()`). You can get runtime errors passing a Chisel type when hardware is expected, and vice versa. + +## Scala Type vs Chisel Type vs Hardware + +```scala mdoc:invisible +import chisel3._ +import chisel3.stage.ChiselStage +``` + +The *Scala* type of the Data is recognized by the Scala compiler, such as `Bool`, `Decoupled[UInt]` or `MyBundle` in +```scala mdoc:silent +class MyBundle(w: Int) extends Bundle { + val foo = UInt(w.W) + val bar = UInt(w.W) +} +``` + +The *Chisel* type of a `Data` is a Scala object. It captures all the fields actually present, +by names, and their types including widths. +For example, `MyBundle(3)` creates a Chisel Type with fields `foo: UInt(3.W), bar: UInt(3.W))`. + +Hardware is `Data` that is "bound" to synthesizable hardware. For example `false.B` or `Reg(Bool())`. +The binding is what determines the actual directionality of each field, it is not a property of the Chisel type. + +A literal is a `Data` that is respresentable as a literal value without being wrapped in Wire, Reg, or IO. + +## Chisel Type vs Hardware vs Literals + +The below code demonstrates how objects with the same Scala type (`MyBundle`) can have different properties. + +```scala mdoc:silent +import chisel3.experimental.BundleLiterals._ + +class MyModule(gen: () => MyBundle) extends Module { + // Hardware Literal + val xType: MyBundle = new MyBundle(3) // - - + val dirXType: MyBundle = Input(new MyBundle(3)) // - - + val xReg: MyBundle = Reg(new MyBundle(3)) // x - + val xIO: MyBundle = IO(Input(new MyBundle(3))) // x - + val xRegInit: MyBundle = RegInit(xIO) // x - + val xLit: MyBundle = xType.Lit( // x x + _.foo -> 0.U(3.W), + _.bar -> 0.U(3.W) + ) + val y: MyBundle = gen() // ? ? + + // Need to initialize all hardware values + xReg := DontCare +} +``` + +```scala mdoc:invisible +// Just here to compile check the above +ChiselStage.elaborate(new MyModule(() => new MyBundle(3))) +``` + +## Chisel Type vs Hardware -- Specific Functions and Errors + +`.asTypeOf` works for both hardware and Chisel type: + +```scala mdoc:silent +ChiselStage.elaborate(new Module { + val chiselType = new MyBundle(3) + val hardware = Wire(new MyBundle(3)) + hardware := DontCare + val a = 0.U.asTypeOf(chiselType) + val b = 0.U.asTypeOf(hardware) +}) +``` + +Can only `:=` to hardware: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new MyBundle(3)) + hardware := DontCare +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { + val chiselType = new MyBundle(3) + chiselType := DontCare +}) +``` + +Can only `:=` from hardware: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardware = IO(new MyBundle(3)) + val moarHardware = Wire(new MyBundle(3)) + moarHardware := DontCare + hardware := moarHardware +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { + val hardware = IO(new MyBundle(3)) + val chiselType = new MyBundle(3) + hardware := chiselType +}) +``` + +Have to pass hardware to `chiselTypeOf`: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new MyBundle(3)) + hardware := DontCare + val chiselType = chiselTypeOf(hardware) +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { + val chiselType = new MyBundle(3) + val crash = chiselTypeOf(chiselType) +}) +``` + +Have to pass hardware to `*Init`: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new MyBundle(3)) + hardware := DontCare + val moarHardware = WireInit(hardware) +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { + val crash = WireInit(new MyBundle(3)) +}) +``` + +Can't pass hardware to a `Wire`, `Reg`, `IO`: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new MyBundle(3)) + hardware := DontCare +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new MyBundle(3)) + val crash = Wire(hardware) +}) +``` + +`.Lit` can only be called on Chisel type: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardwareLit = (new MyBundle(3)).Lit( + _.foo -> 0.U, + _.bar -> 0.U + ) +}) +``` +```scala mdoc:crash +//Not this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new MyBundle(3)) + val crash = hardware.Lit( + _.foo -> 0.U, + _.bar -> 0.U + ) +}) +``` + +Can only use a Chisel type within a `Bundle` definition: +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val hardware = Wire(new Bundle { + val nested = new MyBundle(3) + }) + hardware := DontCare +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { + val crash = Wire(new Bundle { + val nested = Wire(new MyBundle(3)) + }) +}) +``` + +Can only call `directionOf` on Hardware: +```scala mdoc:silent +import chisel3.experimental.DataMirror + +class Child extends Module{ + val hardware = IO(new MyBundle(3)) + hardware := DontCare + val chiselType = new MyBundle(3) +} +``` +```scala mdoc:silent +// Do this... +ChiselStage.elaborate(new Module { + val child = Module(new Child()) + child.hardware := DontCare + val direction = DataMirror.directionOf(child.hardware) +}) +``` +```scala mdoc:crash +// Not this... +ChiselStage.elaborate(new Module { +val child = Module(new Child()) + child.hardware := DontCare + val direction = DataMirror.directionOf(child.chiselType) +}) +``` + +Can call `specifiedDirectionOf` on hardware or Chisel type: +```scala mdoc:silent +ChiselStage.elaborate(new Module { + val child = Module(new Child()) + child.hardware := DontCare + val direction0 = DataMirror.specifiedDirectionOf(child.hardware) + val direction1 = DataMirror.specifiedDirectionOf(child.chiselType) +}) +``` + +## `.asInstanceOf` vs `.asTypeOf` vs `chiselTypeOf` + +`.asInstanceOf` is a Scala runtime cast, usually used for telling the compiler +that you have more information than it can infer to convert Scala types: + +```scala mdoc:silent +class ScalaCastingModule(gen: () => Bundle) extends Module { + val io = gen().asInstanceOf[MyBundle] + io.foo := 0.U +} +``` + +This works if we do indeed have more information than the compiler: +``` scala mdoc:silent +ChiselStage.elaborate(new ScalaCastingModule( () => new MyBundle(3))) +``` + +But if we are wrong, we can get a Scala runtime exception: +```scala mdoc:crash +class NotMyBundle extends Bundle {val baz = Bool()} +ChiselStage.elaborate(new ScalaCastingModule(() => new NotMyBundle())) +``` + +`.asTypeOf` is a conversion from one `Data` subclass to another. +It is commonly used to assign data to all-zeros, as described in [this cookbook recipe](https://www.chisel-lang.org/chisel3/docs/cookbooks/cookbook.html#how-can-i-tieoff-a-bundlevec-to-0), but it can +also be used (though not really recommended, as there is no checking on +width matches) to convert one Chisel type to another: + +```scala mdoc +class SimilarToMyBundle(w: Int) extends Bundle{ + val foobar = UInt((2*w).W) +} + +ChiselStage.emitVerilog(new Module { + val in = IO(Input(new MyBundle(3))) + val out = IO(Output(new SimilarToMyBundle(3))) + + out := in.asTypeOf(out) +}) +``` + +In contrast to `asInstanceOf` and `asTypeOf`, +`chiselTypeOf` is not a casting operation. It returns a Scala object which +can be used as shown in the examples above to create more Chisel types and +hardware with the same Chisel type as existing hardware. diff --git a/docs/src/explanations/data-types.md b/docs/src/explanations/data-types.md index 6ac6077b..67b8e0b9 100644 --- a/docs/src/explanations/data-types.md +++ b/docs/src/explanations/data-types.md @@ -1,6 +1,6 @@ --- layout: docs -title: "Data Types" +title: "Chisel Data Types" section: "chisel3" --- @@ -134,3 +134,4 @@ a <> b a <> b a <> c ``` + diff --git a/docs/src/explanations/explanations.md b/docs/src/explanations/explanations.md index 9e0227d5..762648d0 100644 --- a/docs/src/explanations/explanations.md +++ b/docs/src/explanations/explanations.md @@ -39,3 +39,4 @@ read these documents in the following order: * [Unconnected Wires](unconnected-wires) * [Annotations](annotations) * [Deep Dive into Connection Operators](connection-operators) +* [Chisel Type vs Scala Type](chisel-type-vs-scala-type) -- cgit v1.2.3