diff options
| author | Jack | 2022-07-30 22:41:15 +0000 |
|---|---|---|
| committer | Jack | 2022-07-30 22:41:15 +0000 |
| commit | 4cd44fa4dab370fcc5c20bcacc1fa0ee02327252 (patch) | |
| tree | 05730be260feca0d2a870c4bb88325d36631a8fc /docs/src/explanations/chisel-type-vs-scala-type.md | |
| parent | fe9635ef21bad233945617a24ab16cfa4055f2d1 (diff) | |
| parent | bced77045c8fc5db37e40b159c49220929e15d46 (diff) | |
Merge branch '3.5.x' into 3.5-release
Diffstat (limited to 'docs/src/explanations/chisel-type-vs-scala-type.md')
| -rw-r--r-- | docs/src/explanations/chisel-type-vs-scala-type.md | 285 |
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. |
