Skip to content
apaj edited this page Dec 17, 2021 · 2 revisions

Previous ToC Next

Lazy Modules

A lazy module in Scala is one that has a delay between the point during the run where new MyLazyModule runs, and the point where the constructor for that instance actually runs. The constructor is delayed until the first point at which a function is called on the module.

In Rocket-chip, this is used to solve a problem. The problem is that when connecting things with TileLink, sometimes one end of the connection has a variable size, while the other end has a definite size. In this case, the variable end adapts itself to be the same size as what's on the other end. If the new for the variable end runs first, then the information about the other end is not yet known, and we're stuck.

The solution is to use the lazy module feature. It allows new to run for both ends first, and so the details of both ends are known, and after that, the parameters for both ends are calculated. This happens before any wires are connected. Because no wires have been connected, no constructors have run yet. This way the parameters that the constructors need are calculated after both ends are known, but before the constructors execute. That's what a lazy module enables.

Comments in the code below illustrate the mechanism and details:

// See LICENSE.SiFive for license details.

package freechips.rocketchip.system

import chisel3._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.devices.debug.Debug
import freechips.rocketchip.diplomacy.LazyModule
import freechips.rocketchip.util.AsyncResetReg

class TestHarness()(implicit p: Parameters) extends Module {
  val io = IO(new Bundle { 
    //note: IO automatically comes with clock and reset signals
    val success = Output(Bool())
  })

  val ldut = LazyModule(new ExampleRocketSystem)
  val dut = Module(ldut.module)

  // Allow the debug ndreset to reset the dut, but not until the initial reset has completed
  dut.reset := (reset.asBool | dut.debug.map { debug => AsyncResetReg(debug.ndreset) }.getOrElse(false.B)).asBool

  dut.dontTouchPorts()
  dut.tieOffInterrupts()
  SimAXIMem.connectMem(ldut)
  SimAXIMem.connectMMIO(ldut)
  ldut.l2_frontend_bus_axi4.foreach(_.tieoff)
  Debug.connectDebug(dut.debug, dut.resetctrl, dut.psd, clock, reset.asBool, io.success)
}

Note: extends Module causes circuit generation -- if don't extend Module class, then will be just plain Scala code -- will generate no Verilog Note: IO -- IO in caps is a method defined in Module -- when it defines the "top" inputs and outputs Note: LazyModule is the same as Module, only difference is LazyModule makes Scala wait for the class

//Example of Lazy Module

class TestNumber1()(implicit p: Parameters) extends Module {
  //note: unlike Java, just start writing code -- it is implicitly constructor code unless define a function
  val io = IO(new Bundle {
    val success = Output(Bool())
  })
  val testHarnessInstance = new TestHarness(p) //normally constructor of TestHarness runs here, but it's Lazy, so waits
  
  someFunctionThatAddsKeysTo_p()

  testHarnessInstance.dut.reset := 0.U  //when this line runs is what triggers the constructor of TestHarness to run
  
  // note that p is a struct.  We call that the param struct or just p struct.
  // The actual parameter values are retrieved from the p struct either directly, p.someParam, or by using keys, p(key).  
  // As of Dec 7 2021 we do not fully understand Diplomacy, but the working hypothesis is that new keys can be added
  // by someFunctionThatAddsKeysTo_p.  
  // Ex; someFunctionThatAddsKeysTo_p adds key "foo". This means that, at the point that "new Testharness(p)" was run,
  // there did not exist a "foo" key in p struct. But at the point that testHarnessInstance.dut.reset runs, there _is_
  // a "foo" key in p struct. So the constructor of TestHarness is able to retrieve a value for foo key at the point
  // that the constructor actually runs, whereas it would not have been able to retrieve a value for foo key at the 
  // point that new Testharness() ran.


Previous ToC Top of page Next

Clone this wiki locally