Skip to content
kshalle edited this page Apr 14, 2018 · 17 revisions

Intro

A LazyModule was created to decouple the point in the code where a circuit element is instantiated, from the point in the code where the constructor is called and that instance is actually built. The reason for the delay is that it gives a chance for other calculations to happen, which fill in the parameters that are passed to the constructor.

LazyModule is built on top of Scala's Lazy val mechanism:

Lazy val in Scala

If you put lazy in front of a val definition, the initializing expression on the right-hand side will only be evaluated at the time the val is used (which can be long after the system was initialized and after other computation has completed, such as computation that figured out how you want to initialize the value).

To show the difference, start with example of normal initialization:

object Demo {
  val x = { println("initializing x"); "done" }
}

Now, first refer to Demo, then to Demo.x:

>Demo
initializing x

res3: Demo.type = Demo$@2129a843
Chapter 20 · Abstract Members
>Demo.x
res4: String = done

The "initializing x" shows that as soon as you create Demo, all it's internal vals are also created. The x field was initialed at the same point as Demo was initialized.

Now, see how it's different if x is lazy:

object Demo {
    lazy val x = { println("initializing x"); "done" }
}
defined object Demo
> Demo
res5: Demo.type = Demo$@5b1769c
> Demo.x
initializing x
res6: String = done

Aha, when Demo is initialized, nothing happens with x! Only when you try to get the value of x, does x actually get created. Note that a lazy val is never evaluated more than once. After the first evaluation of a lazy val the result of the evaluation is stored, to be reused when the same val is used subsequently.

More detailed explanations of lazy val usage in Scala, and examples, may be found here.

LazyModule

LazyModule leverages the Lazy val concept, extending it to Chisel Modules. The reason is that the parameterization system needs to do computation before it figures out the interface to a particular module. For example the interface to RocketTile changes dramatically based on what parameter choices are made, and those parameters are not fully known at the point a RockeTile instance is created via "val rTile = RocketTile()". needs to run for a bit before initializing RocketTile.. but.. the scala language needs a place holder, that is created when the language initializes! Hence, LazyModule splits things into two pieces. Once piece is the placeholder class, that initializes when the program starts.. and the second piece is an internal module that initializes after Diplomacy has figured out its interface.

LazyModule is an abstract class of rocket-chip whose complete code is contained in LazyModule.scala found here

LazyModule represents the base for diplomacy and cake pattern, as this abstract class is a module generator that allows postponed (lazy) module elaboration [3].

Classes children of LazyModule are classes that are instantiated only when they are accessed for the first time.

Here are examples found in RocketTile.scala:

val rocket = LazyModule(new RocketTile(rtp, hartid)) // @L158
~
val xing = LazyModule(new IntXing(3)) // @L173
~
val intXbar = LazyModule(new IntXbar) // @L176
~
lazy val module = new LazyModuleImp(this) { // @L183

Point of Lazy Modules in Rocket Chip

The point of making modules "lazy" (read: "not instantiated until accessed for the first time") is to allow the Diplomacy and TileLink to negotiate during the elaboration phase about creating interfaces between those modules. The modules are written in a generic way. Separately, a user will choose parameters, such as which features to include. Then during the elaboration phase, Diplomacy and TileLink "calculate" exactly what is needed for communication between those modules, given the configuration chosen, and instantiate the modules with the appropriate interface.

RocketTile is a LazyModule, the actual implementation is instantiated here

RocketTile uses Diplomacy

References

  1. M. Odersky, Programming in Scala
  2. K. Bhimani, Updates to Sodor
  3. W. Song, Notes for Rocket-Chip
Clone this wiki locally