Chisel logo

Module 5.1: Project Template

Prev: FIRRTL
Next: Combinational Logic

Motivation

Setup

The following cell downloads the dependencies needed for Chisel. You will see it in all future notebooks. Run this cell now.

In [ ]:
val path = System.getProperty("user.dir") + "/source/load-ivy.sc"
interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))

As mentioned in the last module, these statements are needed to import Chisel. Run this cell now before running any future code blocks.

In [ ]:
import chisel3._
import chisel3.util._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.devices.debug.Debug
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper.{HasRegMap, RegField}
import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.{DontTouch, UIntIsOneOf}

Your First Rocketchip Peripheral

This example is based on the project-template repo.

In [ ]:
case class PWMParams(address: BigInt, beatBytes: Int)

class PWMBase(w: Int) extends Module {
  val io = IO(new Bundle {
    val pwmout = Output(Bool())
    val period = Input(UInt(w.W))
    val duty = Input(UInt(w.W))
    val enable = Input(Bool())
  })

  // The counter should count up until period is reached
  val counter = Reg(UInt(w.W))

  when (counter >= (io.period - 1.U)) {
    counter := 0.U
  } .otherwise {
    counter := counter + 1.U
  }

  // If PWM is enabled, pwmout is high when counter < duty
  // If PWM is not enabled, it will always be low
  io.pwmout := io.enable && (counter < io.duty)
}

trait PWMTLBundle extends Bundle {
  val pwmout = Output(Bool())
}

trait PWMTLModule extends HasRegMap {
  val io: PWMTLBundle
  implicit val p: Parameters
  def params: PWMParams

  // How many clock cycles in a PWM cycle?
  val period = Reg(UInt(32.W))
  // For how many cycles should the clock be high?
  val duty = Reg(UInt(32.W))
  // Is the PWM even running at all?
  val enable = RegInit(false.B)

  val base = Module(new PWMBase(32))
  io.pwmout := base.io.pwmout
  base.io.period := period
  base.io.duty := duty
  base.io.enable := enable

  regmap(
    0x00 -> Seq(
      RegField(32, period)),
    0x04 -> Seq(
      RegField(32, duty)),
    0x08 -> Seq(
      RegField(1, enable)))
}

class PWMTL(c: PWMParams)(implicit p: Parameters)
  extends TLRegisterRouter(
    c.address, "pwm", Seq("ucbbar,pwm"),
    beatBytes = c.beatBytes)(
      new TLRegBundle(c, _) with PWMTLBundle)(
      new TLRegModule(c, _, _) with PWMTLModule)

trait HasPeripheryPWM { this: BaseSubsystem =>
  implicit val p: Parameters

  private val address = 0x2000
  private val portName = "pwm"

  val pwm = LazyModule(new PWMTL(
    PWMParams(address, pbus.beatBytes))(p))

  pbus.toVariableWidthSlave(Some(portName)) { pwm.node }
}

trait HasPeripheryPWMModuleImp extends LazyModuleImp {
  implicit val p: Parameters
  val outer: HasPeripheryPWM

  val pwmout = IO(Output(Bool()))

  pwmout := outer.pwm.module.io.pwmout
}

class RocketWithPWM(implicit p: Parameters) extends RocketSubsystem
    with HasAsyncExtInterrupts
    with CanHaveMasterAXI4MemPort
    with CanHaveMasterAXI4MMIOPort
    with CanHaveSlaveAXI4Port
    with HasPeripheryBootROM
    with HasPeripheryPWM {
  override lazy val module = new RocketWithPWMModule(this)
}

class RocketWithPWMModule(l: RocketWithPWM) extends RocketSubsystemModuleImp(l)
    with HasRTCModuleImp
    with HasExtInterruptsModuleImp
    with CanHaveMasterAXI4MemPortModuleImp
    with CanHaveMasterAXI4MMIOPortModuleImp
    with CanHaveSlaveAXI4PortModuleImp
    with HasPeripheryBootROMModuleImp
    with DontTouch
    with HasPeripheryPWMModuleImp

class TestHarness extends Module {
  implicit val p: Parameters = new freechips.rocketchip.system.DefaultConfig
  override def desiredName = "TestHarness"

  val io = IO(new Bundle {
    val success = Output(Bool())
  })

  val dut = Module(LazyModule(new RocketWithPWM).module)
  dut.dontTouchPorts()
  dut.tieOffInterrupts()
  dut.connectSimAXIMem()
  dut.connectSimAXIMMIO()
  dut.l2_frontend_bus_axi4.foreach(a => {
      a.tieoff()
      a.ar.bits := DontCare
      a.aw.bits := DontCare
      a.w.bits := DontCare
  })
  Debug.connectDebug(dut.debug, clock, reset.toBool, io.success)
}

// println(getFirrtl(new TestHarness))
chisel3.Driver.execute(Array[String]("-X", "verilog", "-td", "./verisim/generated-src/"), () => new TestHarness)

You're done!

Return to the top.

In [ ]: