From 905c9a14f68e39e2e71738bd3e1868c3f1297453 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 26 Oct 2016 11:53:13 -0700 Subject: [PATCH] have TL and AXI based PWM controllers --- src/main/scala/pwm/Configs.scala | 25 ++++++- src/main/scala/pwm/PWM.scala | 115 +++++++++++++++++++++++++------ 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/src/main/scala/pwm/Configs.scala b/src/main/scala/pwm/Configs.scala index 26a34143..bd5b6d68 100644 --- a/src/main/scala/pwm/Configs.scala +++ b/src/main/scala/pwm/Configs.scala @@ -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) diff --git a/src/main/scala/pwm/PWM.scala b/src/main/scala/pwm/PWM.scala index e151f35f..c857c7a4 100644 --- a/src/main/scala/pwm/PWM.scala +++ b/src/main/scala/pwm/PWM.scala @@ -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) }