127 lines
3.2 KiB
Scala
127 lines
3.2 KiB
Scala
package example
|
|
|
|
import chisel3._
|
|
import chisel3.util._
|
|
import freechips.rocketchip.amba.axi4._
|
|
import freechips.rocketchip.subsystem.BaseSubsystem
|
|
import freechips.rocketchip.config.{Parameters, Field}
|
|
import freechips.rocketchip.diplomacy._
|
|
import freechips.rocketchip.regmapper.{HasRegMap, RegField}
|
|
import freechips.rocketchip.tilelink._
|
|
import freechips.rocketchip.util.UIntIsOneOf
|
|
|
|
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 PWMBundle extends Bundle {
|
|
val pwmout = Output(Bool())
|
|
}
|
|
|
|
trait PWMModule extends HasRegMap {
|
|
val io: PWMBundle
|
|
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 PWMBundle)(
|
|
new TLRegModule(c, _, _) with PWMModule)
|
|
|
|
class PWMAXI4(c: PWMParams)(implicit p: Parameters)
|
|
extends AXI4RegisterRouter(c.address, beatBytes = c.beatBytes)(
|
|
new AXI4RegBundle(c, _) with PWMBundle)(
|
|
new AXI4RegModule(c, _, _) with PWMModule)
|
|
|
|
trait HasPeripheryPWMTL { 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 HasPeripheryPWMTLModuleImp extends LazyModuleImp {
|
|
implicit val p: Parameters
|
|
val outer: HasPeripheryPWMTL
|
|
|
|
val pwmout = IO(Output(Bool()))
|
|
|
|
pwmout := outer.pwm.module.io.pwmout
|
|
}
|
|
|
|
trait HasPeripheryPWMAXI4 { this: BaseSubsystem =>
|
|
implicit val p: Parameters
|
|
|
|
private val address = 0x2000
|
|
private val portName = "pwm"
|
|
|
|
val pwm = LazyModule(new PWMAXI4(
|
|
PWMParams(address, pbus.beatBytes))(p))
|
|
|
|
pbus.toSlave(Some(portName)) {
|
|
pwm.node :=
|
|
AXI4Buffer () :=
|
|
TLToAXI4() :=
|
|
// toVariableWidthSlave doesn't use holdFirstDeny, which TLToAXI4() needs
|
|
TLFragmenter(pbus.beatBytes, pbus.blockBytes, holdFirstDeny = true)
|
|
}
|
|
}
|
|
|
|
trait HasPeripheryPWMAXI4ModuleImp extends LazyModuleImp {
|
|
implicit val p: Parameters
|
|
val outer: HasPeripheryPWMAXI4
|
|
|
|
val pwmout = IO(Output(Bool()))
|
|
|
|
pwmout := outer.pwm.module.io.pwmout
|
|
}
|