have TL and AXI based PWM controllers

This commit is contained in:
Howard Mao 2016-10-26 11:53:13 -07:00
parent a9e741fbce
commit 905c9a14f6
2 changed files with 119 additions and 21 deletions

View File

@ -2,5 +2,28 @@ package pwm
import cde.{Parameters, Config, CDEMatchError}
import testchipip.WithSerialAdapter
import uncore.tilelink.ClientUncachedTileLinkIO
import rocketchip.PeripheryUtils
import chisel3._
class PWMConfig extends Config(new example.DefaultExampleConfig)
class WithPWMAXI extends Config(
(pname, site, here) => pname match {
case BuildPWM => (port: ClientUncachedTileLinkIO, p: Parameters) => {
val pwm = Module(new PWMAXI()(p))
pwm.io.axi <> PeripheryUtils.convertTLtoAXI(port)
pwm.io.pwmout
}
case _ => throw new CDEMatchError
})
class WithPWMTL extends Config(
(pname, site, here) => pname match {
case BuildPWM => (port: ClientUncachedTileLinkIO, p: Parameters) => {
val pwm = Module(new PWMTL()(p))
pwm.io.tl <> port
pwm.io.pwmout
}
})
class PWMAXIConfig extends Config(new WithPWMAXI ++ new example.DefaultExampleConfig)
class PWMTLConfig extends Config(new WithPWMTL ++ new example.DefaultExampleConfig)

View File

@ -2,16 +2,38 @@ package pwm
import chisel3._
import chisel3.util._
import cde.Parameters
import cde.{Parameters, Field}
import uncore.tilelink._
import junctions._
import diplomacy._
import rocketchip._
class PWM(implicit p: Parameters) extends Module {
class PWMBase extends Module {
val io = new Bundle {
val pwmout = Bool(OUTPUT)
val tl = (new ClientUncachedTileLinkIO).flip
val period = UInt(INPUT, 64)
val duty = UInt(INPUT, 64)
val enable = Bool(INPUT)
}
// The counter should count up until period is reached
val counter = Reg(UInt(width = 64))
when (counter >= (io.period - UInt(1))) {
counter := UInt(0)
} .otherwise {
counter := counter + UInt(1)
}
// 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(implicit p: Parameters) extends Module {
val io = new Bundle {
val pwmout = Bool(OUTPUT)
val tl = new ClientUncachedTileLinkIO().flip
}
// How many clock cycles in a PWM cycle?
@ -21,18 +43,11 @@ class PWM(implicit p: Parameters) extends Module {
// Is the PWM even running at all?
val enable = Reg(init = Bool(false))
// The counter should count up until period is reached
val counter = Reg(UInt(width = 64))
when (counter >= period) {
counter := UInt(0)
} .otherwise {
counter := counter + UInt(1)
}
// If PWM is enabled, pwmout is high when counter < duty
// If PWM is not enabled, it will always be low
io.pwmout := enable && (counter < duty)
val base = Module(new PWMBase)
io.pwmout := base.io.pwmout
base.io.period := period
base.io.duty := duty
base.io.enable := enable
// One entry queue to hold the acquire message
val acq = Queue(io.tl.acquire, 1)
@ -48,8 +63,11 @@ class PWM(implicit p: Parameters) extends Module {
// Make sure the acquires we get are only the types we expect
assert(!acq.valid ||
acq.bits.isBuiltInType(Acquire.getType) ||
acq.bits.isBuiltInType(Acquire.putType),
"PWM: unexpected acquire type")
acq.bits.isBuiltInType(Acquire.putType))
// Make sure write masks are full
assert(!acq.valid || !acq.bits.hasData() ||
acq.bits.wmask() === Acquire.fullWriteMask)
// Base the grant on the stored acquire
io.tl.grant.valid := acq.valid
@ -76,6 +94,63 @@ class PWM(implicit p: Parameters) extends Module {
}
}
class PWMAXI(implicit p: Parameters) extends Module {
val io = new Bundle {
val pwmout = Bool(OUTPUT)
val axi = new NastiIO().flip
}
// How many clock cycles in a PWM cycle?
val period = Reg(UInt(width = 64))
// For how many cycles should the clock be high?
val duty = Reg(UInt(width = 64))
// Is the PWM even running at all?
val enable = Reg(init = Bool(false))
val base = Module(new PWMBase)
io.pwmout := base.io.pwmout
base.io.period := period
base.io.duty := duty
base.io.enable := enable
val ar = Queue(io.axi.ar, 1)
val aw = Queue(io.axi.aw, 1)
val w = Queue(io.axi.w, 1)
// Start from 3rd bit since 64-bit words
// Only need 2 bits, since 3 registers
val read_index = ar.bits.addr(4, 3)
val write_index = aw.bits.addr(4, 3)
io.axi.r.valid := ar.valid
ar.ready := io.axi.r.ready
io.axi.r.bits := NastiReadDataChannel(
id = ar.bits.id,
data = MuxLookup(read_index, UInt(0), Seq(
UInt(0) -> period,
UInt(1) -> duty,
UInt(2) -> enable)))
io.axi.b.valid := aw.valid && w.valid
aw.ready := io.axi.b.ready && w.valid
w.ready := io.axi.b.ready && aw.valid
io.axi.b.bits := NastiWriteResponseChannel(id = aw.bits.id)
when (io.axi.b.fire()) {
switch (write_index) {
is (UInt(0)) { period := w.bits.data }
is (UInt(1)) { duty := w.bits.data }
is (UInt(2)) { enable := w.bits.data(0) }
}
}
require(io.axi.w.bits.nastiXDataBits == 64)
assert(!io.axi.ar.valid || (io.axi.ar.bits.len === UInt(0) && io.axi.ar.bits.size === UInt(3)))
assert(!io.axi.aw.valid || (io.axi.aw.bits.len === UInt(0) && io.axi.aw.bits.size === UInt(3)))
assert(!io.axi.w.valid || PopCount(io.axi.w.bits.strb) === UInt(8))
}
trait PeripheryPWM extends LazyModule {
val pDevices: ResourceManager[AddrMapEntry]
@ -86,12 +161,12 @@ trait PeripheryPWMBundle {
val pwmout = Bool(OUTPUT)
}
case object BuildPWM extends Field[(ClientUncachedTileLinkIO, Parameters) => Bool]
trait PeripheryPWMModule extends HasPeripheryParameters {
implicit val p: Parameters
val pBus: TileLinkRecursiveInterconnect
val io: PeripheryPWMBundle
val pwm = Module(new PWM()(outerMMIOParams))
pwm.io.tl <> pBus.port("pwm")
io.pwmout := pwm.io.pwmout
io.pwmout := p(BuildPWM)(pBus.port("pwm"), outerMMIOParams)
}