chipsalliance / rocket-chip

Rocket Chip Generator
Other
3.26k stars 1.13k forks source link

Produce a Module wrapper for a LazyModule #964

Closed wsong83 closed 7 years ago

wsong83 commented 7 years ago

What I really want is to produce Verilog from a LazyModule without knowning its IO bundles.

For what I understand, the current GeneratorApp accepts Module, rather than LazyModule. Therefore, I need to produce a Module wrapper which contains the LazyModule as a DUT.

However, I do not want to set the IO bundle statically as the parameters may affect the IO bundle. Here is what I did:

class CoreplexTop()(implicit p: Parameters) extends RawModule {

  val coreplex = LazyModule(new ExampleRocketSystem)
  val clk = IO(Input(Clock()))
  val rst = IO(Input(Bool()))
  val interrupts = IO(UInt(INPUT, width = coreplex.nExtInterrupts))
  val mem = IO(coreplex.mem_axi4.bundleOut)
  val mmio_master = IO(coreplex.mmio_axi4.bundleOut)
  val mmio_slave = IO(coreplex.l2FrontendAXI4Node.bundleIn)

  withClockAndReset(clk, rst) {
    val rocket = Module(coreplex.module)

    rocket.interrupts <> interrupts
    mem <> rocket.mem_axi4
    mmio_master <> rocket.mmio_axi4
    rocket.l2_frontend_bus_axi4 <> mmio_slave
  }
}

However, this does not work because the IO() is applied twice. I think the problem is the bundleIn and bundleOut are val produced by MixedNode. Then this IO() is applied twice.

Is there a proper way that I can get a IO bundle cloned from a module? Also, is there a way to inspect all IO bundles of a module generated by a LazyMultiIOModuleImp? I assume the IO in such a module is not named after io?

wsong83 commented 7 years ago

Nearly there.

So I can produce Verilog using the following:

class CoreplexTop()(implicit p: Parameters) extends RawModule {

  val coreplex = LazyModule(new ExampleRocketSystem)
  val clk = IO(Input(Clock()))
  val rst = IO(Input(Bool()))
  val interrupts = IO(UInt(INPUT, width = coreplex.nExtInterrupts))
  val mem = IO(coreplex.mem_axi4.bundleOut.cloneType)
  val mmio_master = IO(coreplex.mmio_axi4.bundleOut.cloneType)
  //val mmio_slave = IO(coreplex.l2FrontendAXI4Node.bundleIn.cloneType)

  withClockAndReset(clk, rst) {
    val rocket = Module(coreplex.module)

    rocket.interrupts <> interrupts
    mem <> rocket.mem_axi4
    mmio_master <> rocket.mmio_axi4
    //rocket.l2_frontend_bus_axi4 <> mmio_slave
  }
}

However, cloneType does not work for mmio_slave. FIRRTL complains:

[module CoreplexTop] Expression mmio_slave is used as a MALE but can only be used as a FEMALE.

wsong83 commented 7 years ago

Changing

val mmio_slave = IO(coreplex.l2FrontendAXI4Node.bundleIn.cloneType)

to

val mmio_slave = IO(Flipped(coreplex.l2FrontendAXI4Node.bundleIn.cloneType))

did the trick. But I do not understand why I need to add the Flipped() here.

Happy for this issue to be closed if this behaviour is expected.

terpstra commented 7 years ago

Nice work fixing this on your own. You needed Flipped, because cloneType wipes away the direction. The default direction of an AXI4 bundle is master IOs as outputs.

wsong83 commented 7 years ago

Thanks for the clarification on cloneType.

edcote commented 7 years ago

(comment only)

Thank you Sir. I referred to this issue when facing a similar problem. For future readers, you can apply the same technique to debug pins.

val interrupts = IO(Input(UInt(width = 1))) val debug = IO(new DebugIO()) [..] dut.interrupts := interrupts debug <> dut.debug