diff options
Diffstat (limited to 'docs/src/explanations')
| -rw-r--r-- | docs/src/explanations/chisel-type-vs-scala-type.md | 285 | ||||
| -rw-r--r-- | docs/src/explanations/data-types.md | 3 | ||||
| -rw-r--r-- | docs/src/explanations/explanations.md | 1 |
3 files changed, 288 insertions, 1 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. 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) |
