Files
chipyard/src/main/scala/pwm/PWM.scala
2017-04-20 18:12:44 -07:00

128 lines
3.5 KiB
Scala

package pwm
import chisel3._
import chisel3.util._
import config.{Parameters, Field}
import uncore.tilelink._
import uncore.tilelink2._
import junctions._
import diplomacy._
import rocketchip._
import _root_.util.UIntIsOneOf
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)
}
class PWMTL(address: AddressSet, beatBytes: Int)(implicit p: Parameters) extends LazyModule {
val node = TLManagerNode(Seq(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(address),
regionType = RegionType.PUT_EFFECTS,
executable = false,
supportsGet = TransferSizes(1, beatBytes),
supportsPutFull = TransferSizes(1, beatBytes),
fifoId = Some(0))), // requests are handled in order
beatBytes = beatBytes,
minLatency = 1)))
lazy val module = new PWMTLModule(this, beatBytes)
}
class PWMTLModule(outer: PWMTL, beatBytes: Int) extends LazyModuleImp(outer) {
val io = IO(new Bundle {
val pwmout = Output(Bool())
val tl = outer.node.bundleIn
})
val w = beatBytes * 8
// How many clock cycles in a PWM cycle?
val period = Reg(UInt(w.W))
// For how many cycles should the clock be high?
val duty = Reg(UInt(w.W))
// Is the PWM even running at all?
val enable = Reg(init = false.B)
val base = Module(new PWMBase(w))
io.pwmout := base.io.pwmout
base.io.period := period
base.io.duty := duty
base.io.enable := enable
val tl = io.tl.head
tl.b.valid := false.B
tl.c.ready := false.B
tl.e.ready := false.B
// One entry queue to hold the acquire message
val acq = Queue(tl.a, 1)
// We have 3 32-bit registers
val index = acq.bits.address(3, 2)
val edge = outer.node.edgesIn(0)
val hasData = edge.hasData(acq.bits)
// Base the grant on the stored acquire
tl.d.valid := acq.valid
acq.ready := tl.d.ready
tl.d.bits := edge.AccessAck(acq.bits, 0.U)
tl.d.bits.opcode := Mux(hasData, TLMessages.AccessAck, TLMessages.AccessAckData)
tl.d.bits.data := MuxLookup(index, 0.U,
Seq(
0.U -> period,
1.U -> duty,
2.U -> enable))
tl.d.bits.error := index > 2.U
// If this is a put, update the registers according to the index
when (acq.fire() && acq.bits.opcode === TLMessages.PutFullData) {
switch (index) {
is (0.U) { period := acq.bits.data }
is (1.U) { duty := acq.bits.data }
is (2.U) { enable := acq.bits.data(0) }
}
}
}
trait PeripheryPWM extends LazyModule with HasPeripheryParameters {
implicit val p: Parameters
val peripheryBus: TLXbar
private val address = AddressSet(0x2000, 0xfff)
val pwm = LazyModule(new PWMTL(address, peripheryBusConfig.beatBytes)(p))
pwm.node := TLFragmenter(
peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
}
trait PeripheryPWMBundle {
val pwmout = Output(Bool())
}
trait PeripheryPWMModule extends HasPeripheryParameters {
implicit val p: Parameters
val io: PeripheryPWMBundle
val outer: PeripheryPWM
io.pwmout := outer.pwm.module.io.pwmout
}