Chisel Breakdown 2
Jack Koenig, SiFive
Purpose of this Talk
2
What Is Chisel? (from many past talks)
3
What Is Chisel… Really?
4
Chisel To Verilog
5
Where are errors caught?
6
Simple Elaboration Example
DefWire(_, UInt(8.W))
DefPrim(_, _wire_T, BitAndOp, Seq(foo, bar))
Connect(_, wire, _wire_T)
7
In ChiselIR, these are called Commands
Stored in the containing Module (called Component in ChiselIR)
val wire = Wire(UInt(8.W))�wire := foo & bar
Binding (Chisel’s type system)
val template: UInt = UInt(8.W) // This is a Type�val wire: UInt = Wire(template) // This is a Value�template.getClass == wire.getClass // true�template === wire // Binding exception, template is not hardware
8
Chisel Project Structure
9
We use subprojects because a Scala macro cannot be used in the same compilation unit within which it was defined
macros/
10
core/
11
chisel3 (src/main/scala/chisel3/)
12
plugin/
13
docs/ - Documentation That Works
14
docs/ - Documentation That Works
### Bundle Literals <a name="bundle-literals"></a>��Bundle literals can be constructed via an experimental import:��```scala mdoc�import chisel3._�import chisel3.experimental.BundleLiterals._��class MyBundle extends Bundle {� val a = UInt(8.W)� val b = Bool()�}��class Example extends RawModule {� val out = IO(Output(new MyBundle))� out := (new MyBundle).Lit(_.a -> 8.U, _.b -> true.B)�}�```��```scala mdoc:verilog�chisel3.stage.ChiselStage.emitVerilog(new Example)�```
15
ChiselStage (replaces Driver)
16
Builder
17
CompileOptions (Compatibility Mode)
18
Source Locators
Recall that SourceInfoTransform is defined in macros while SourceInfo is defined in core
From Bits.scala (core)
final def & (that: Bool): Bool = macro SourceInfoTransform.thatArg
def do_& (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
All SourceInfoTransform does is replace invocations of & in user code with do_&
Why is this useful?
19
Source Locators
final def & (that: Bool): Bool = macro SourceInfoTransform.thatArg
def do_& (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
Allows chaining apply (bit extract) after &
(myWire & 0xf0.U)(5)�myWire.&(0xf0.U)(5)
Without SourceInfoTransform, Scala would look for SourceInfo and CompileOptions in the second parameter list
20
Reflective Naming
class MyModule extends Module {� val io = IO(...) // nameable� val wire = Wire(UInt(8.W)) // nameable� def func() = {� val reg = Reg(UInt(8.W) // NOT nameable by reflection� io.out := reg + wire� }�}
21
Chisel Naming Plugin (replaces @chiselName)
The compiler plugin inspects your Chisel source code, finding Data objects that are assigned to vals and inserting both naming and prefixing
class Example extends RawModule {� val a, b, c = IO(Input(UInt(8.W)))� val out = IO(Output(UInt()))� def func() = {� val x = a + b� val y = x - 3.U� y & 0xcf.U� }� val result = func() | 0x8.U� out := result�}
22
Chisel Naming Plugin
def func() = {� val x = a + b� val y = x - 3.U� y & 0xcf.U�}�val result = func() | 0x8.U�out := result
wire [7:0] result_x = a + b; // @[main.scala 11:15]�wire [7:0] result_y = result_x - 8'h3; // @[main.scala 12:15]�wire [7:0] _result_T = result_y & 8'hcf; // @[main.scala 13:7]�assign out = _result_T | 8'h8; // @[main.scala 15:23]
23
Chisel Naming Plugin
def func() = {� // val x = a + b� val x = autoNameRecursively("x")(prefix("x")(a + b))� // val y = x - 3.U� val y = autoNameRecursively("y")(prefix("y")(x - 3.U))� y & 0xcf.U�}�// val result = func() | 0x8.U�val result = autoNameRecursively("result")(prefix("result")(func() | 0x8.U))�out := result // := also prefixes based on the LHS
24
CloneType - What & Why
Because Chisel Types are immutable objects, we need to create fresh instances of them in order to create hardware, add directions, etc.
val gen = new Bundle { val foo = Input(UInt(8.W)) } �val io = IO(gen) // We can use gen as a type template�val w = Wire(gen) // multiple times�w <> io
�We need the ability to create copies of any Data object
25
CloneType
class MyBundle(w: Int) extends Bundle {� val field = UInt(w.W)�� override def cloneType: this.type =� new MyBundle(w).asInstanceOf[this.type]�}
26
Plugin AutoCloneType (aka autoclonetype2)
27
Plugin AutoCloneType (aka autoclonetype2)
class MyBundle(w: Int) extends Bundle {� val field = UInt(w.W)�� // Generated by the compiler plugin� override protected def _cloneTypeImpl: Bundle = new MyBundle(w)� override protected def _usingPlugin: Boolean = true�}
abstract class Bundle {� override def cloneType: this.type = {� val clone = _cloneTypeImpl.asInstanceOf[this.type]� checkClone(clone)� clone� }�}
28
Aspects
29
Questions?
30
Extra / Old Slides
31
Types
32
Widths
val x = io.in * io.in
println(x.getWidth) // 16
val y = WireInit(x * x)
println(y.getWidth) // 32
val z = Wire(UInt())
z := y * y
println(z.getWidth) // Exception
33
Why do we have to wrap Modules in Module(...)
object Foo {
def addOne(x: UInt): UInt = x + 1
}
34
DynamicContext
35
ChiselContext
36
Record vs. Bundle
val elements: ListMap[String, Data]
Bundles use reflection to find and generate these elements
class MyBundle {
val foo = UInt(8.W)
}
37
IntelliJ/IDE Tips
38
@chiselName
@chiselName is a macro that inspects the body of any class or object and finds Chisel Data elements that get assigned to a val which it then names
@chiselName
class MyModule extends Module {
val io = IO(...) // nameable
val wire = Wire(UInt(8.W)) // nameable
def func() = {
val reg = Reg(UInt(8.W) // nameable by @chiselName
io.out := reg + wire
}
}
39
Auto-CloneType
class MyBundle(val width: Int) extends Bundle {
val field = UInt(width.W)
}
What about inner classes?
40
Auto-CloneType (Inner Classes)
class MyModule(width: Int) extends Module {
class MyBundle extends Bundle {
val field = UInt(width.W)
}
}
41
Auto-CloneType (Inner Classes)
class MyModule(width: Int) extends Module { self =>
class MyBundle(outer: MyModule) extends Bundle {
val field = UInt(outer.width.W)
}
val io = IO(Output(new MyBundle(self)))
}
42
Auto-CloneType (Anonymous Inner Classes)
class MyModule(width: Int) extends Module {
val io = IO(new Bundle {
val field = Output(UInt(width.W))
})
}
43
Auto-CloneType (Nested Bundles)
class MyOuterBundle extends Bundle {
val foo = new Bundle {
val bar = UInt(8.W)
}
}
44
Auto-CloneType (Nested Bundles)
45
A word on package.scala
package object chisel3 { …
In Scala, all defs and vals must be defined in an object or class. This lets us define defs and vals that are included in import chisel3._
Why is this useful? For example, type aliasing:�� @deprecated("MultiIOModule is now just Module", "Chisel 3.5")� type MultiIOModule = chisel3.Module��We used to use this for all types, but type aliasing results�in bad API docs. Used extensively for import Chisel._
46
First, some FAQ
Q: Why multiple projects?�A: Scala macros cannot be used in the same project where they were defined
Q: Why {project}/src/main/scala?�A: This is where SBT expects source files, this comes from Maven
47
Chisel Simulation Flow
48