summaryrefslogtreecommitdiff
path: root/docs/src/explanations/chisel-type-vs-scala-type.md
diff options
context:
space:
mode:
authormergify[bot]2022-07-25 13:36:26 +0000
committerGitHub2022-07-25 13:36:26 +0000
commitb8f884e15114b7c9f29b1ec8f23a4216bcbfca76 (patch)
treec1380eebc87808b51a9fd3e8f882d7dd082f4894 /docs/src/explanations/chisel-type-vs-scala-type.md
parent0ff14a949f6781f5d76c6088202863d16cb24a18 (diff)
Add an Explanation chapter about Scala types vs Chisel Types vs Hardware (#2626) (#2642)
(cherry picked from commit 81fcf229da84e334cdc466ffbb8ea74c7975a4a9) Co-authored-by: Megan Wachs <megan@sifive.com>
Diffstat (limited to 'docs/src/explanations/chisel-type-vs-scala-type.md')
-rw-r--r--docs/src/explanations/chisel-type-vs-scala-type.md285
1 files changed, 285 insertions, 0 deletions
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.